[工学]程序设计与问题求解Ⅱ.ppt_第1页
[工学]程序设计与问题求解Ⅱ.ppt_第2页
[工学]程序设计与问题求解Ⅱ.ppt_第3页
[工学]程序设计与问题求解Ⅱ.ppt_第4页
[工学]程序设计与问题求解Ⅱ.ppt_第5页
已阅读5页,还剩64页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第5章 继承与派生,2012.2.21,2,本章主要内容,类的继承与派生 派生类 派生类的继承方式与访问属性 派生类的构造函数和析构函数 多继承 赋值兼容原则,3,继承与派生问题,客观世界中概念的层次结构,视角:从下往上看,保持已有的特性继承 视角:从上往下看,增加了新的特性派生,继承,派生,4,继承与派生问题举例(1),5,继承与派生问题举例(2),6,类的继承与派生(1),类的层次结构 类的继承:一个新类从原有的类那里获得其已有的特性 类的派生:从已有的类产生一个新的类 基类(父类):派生新类的类 派生类(子类):从基类派生而成的类,学生类,研究生,基类,7,类的继承与派生(2),基类和派生类:构成类的层次关系 单派生:派生一个子类的类 多派生:派生多个子类的类,学生类,研究生,基类,例如上图: 单派生:大学生派生研究生。 多派生:除了一个单派生其余的都是多派生。,多派生,8,类的继承与派生(3),基类和派生类:构成类的层次关系 单继承:仅从一个基类派生而成的类 多继承:从多个基类派生而成的类,派生类,在职研究生,研究生,在职人员,在面向对象程序设计中使用继承和派生有什么好处? 如何使用?,多继承,例如上图: 单继承:教师和职员都是单继承,只有一个父类。 多继承:在职研究生就是多继承,有两个父类。,9,类的继承与派生(4),class Person /人的基本信息 char Name20; char Sex; int Age; public: void Register(char *name, char sex, int age) strcpy(Name, name); Sex = (sex = m?m:f); Age = age; void ShowMe() cout Name t Sex t Age endl; ;,10,类的继承与派生(5),class Student /学生类 char Name20; char Sex; int Age; int Number; /学号 char ClassName10; /班级 public: void RegisterStu(char *name, int sex, char age, int number, char *classname) strcpy(Name, name); Sex = (sex = m?m:f); Age = age; Number = number; strcpy(ClassName, classname); void ShowStu() cout Name t Sex t Age endl; cout Number t ClassName endl; ;,从这个例子我们能发现什么?,能否利用已有的代码?,11,类的继承与派生(6),class Student:public Person /公有继承 int Number; /学号 char ClassName10; /班级 public: void RegisterStu(char *name, int sex, char age, int number, char *classname) Register(name, sex, age); /直接调用基类的公有成员 Number = number; strcpy(ClassName, classname); void ShowStu() ShowMe(); /直接调用基类的公有成员 cout Number t ClassName endl; ;,继承与派生:Student是派生类,Person是基类 继承已有的特性,派生新的特性,12,继承的目的:保持已有的特性,实现代码重用。 派生的目的:增加新的特性,适应新的需要。 类的继承:保留已有的数据成员和成员函数 类的派生:增加新的数据成员和成员函数,类的继承与派生(7),在面向对象程序设计中如何使用继承和派生?,13,派生类的定义格式 class 派生类名:继承方式 基类名 新增成员声明; ; 继承方式 公有继承(public) 私有继承(private) 保护继承(protected),派生类定义,14,派生类对象结构,class A int a , b ; ; class B : public A int c ; ;,基类A对象 子类B对象,派生类对象中总是含有基类对象(即含有基类的数据成员),其空间总是不小于基类对象。,15,类的成员访问属性有三种:public(公有)、private (私有)和protected (保护)。 在类内,非静态成员函数可以访问类中的所有成员。 在类外,通过类的“对象.成员”方式只能访问该类的公有成员。 类的继承方式有三种:public(公有继承)、private(私有继承)和protected(保护继承)。 在派生类中继承来的成员访问属性是什么?继承来的成员是不是都可以直接访问?,派生类的继承方式和访问属性(1),16,继承方式下的访问权限,17,派生类的继承方式和访问属性(2),public(公有继承) class Person char Name20; char Sex; int Age; public: void Register(char *name, char sex, int age) strcpy(Name, name); Sex = (sex = m?m:f); Age = age; void ShowMe() cout Name t Sex t Age endl; ;,class Student:public Person /公有继承 int Number; /学号 char ClassName10; /班级 public: void RegisterStu(char *name, int sex, char age, int number, char *classname) Register(name, sex, age); Age=age; Number = number; strcpy(ClassName, classname); void ShowStu() ShowMe(); cout Number t ClassName endl; ;,18,派生类的继承方式和访问属性(续),public(公有继承) int main() Student stu; /定义一个对象 stu.RegisterStu(“张弓长“, m,18, 85071011, “计算机51“);/本类中的公有成员函数 stu.Age=18; /基类的私有数据成员 stu.Number=110012315; /本类中的私有数据成员 stu.ShowStu(); /本类中的公有成员函数 stu.ShowMe(); /基类的,成为派生类的公有成员函数 return 0; ,19,派生类的继承方式和访问属性(续),public(公有继承) class Person protected: char Name20; char Sex; int Age; public: void Register(char *name, char sex, int age) strcpy(Name, name); Sex = (sex = m?m:f); Age = age; void ShowMe() cout Name t Sex t Age endl; ;,class Student:public Person /公有继承 int Number; /学号 char ClassName10; /班级 public: void RegisterStu(char *name, int sex, char age, int number, char *classname) Register(name, sex, age); Age=age; Number = number; strcpy(ClassName, classname); void ShowStu() ShowMe(); cout Number t ClassName endl; ;,20,派生类的继承方式和访问属性(3),protected(保护继承) class Person char Name20; char Sex; int Age; public: void Register(char *name, char sex, int age) strcpy(Name, name); Sex = (sex = m?m:f); Age = age; void ShowMe() cout Name t Sex t Age endl; ;,class Student:protected Person /保护继承 int Number; /学号 char ClassName10; /班级 public: void RegisterStu(char *name, int sex, char age, int number, char *classname) Register(name, sex, age); Age=age; Number = number; strcpy(ClassName, classname); void ShowStu() ShowMe(); cout Number t ClassName endl; ;,21,派生类的继承方式和访问属性(续),protected(保护继承) int main() Student stu; stu.RegisterStu(“张弓长“, m,18, 85071011, “计算机51“); stu.Age=18; /基类的私有数据成员 stu.ShowStu(); stu.ShowMe(); /成为派生类的保护成员 return 0; ,22,派生类的继承方式和访问属性(续),protected(保护继承) class Person protected: char Name20; char Sex; int Age; public: void Register(char *name, char sex, int age) strcpy(Name, name); Sex = (sex = m?m:f); Age = age; void ShowMe() cout Name t Sex t Age endl; ;,class Student:protected Person /保护继承 int Number; /学号 char ClassName10; /班级 public: void RegisterStu(char *name, int sex, char age, int number, char *classname) Register(name, sex, age); Age=age; Number = number; strcpy(ClassName, classname); void ShowStu() ShowMe(); cout Number t ClassName endl; ;,23,派生类的继承方式和访问属性(4),private(私有继承) class Person char Name20; char Sex; int Age; public: void Register(char *name, char sex, int age) strcpy(Name, name); Sex = (sex = m?m:f); Age = age; void ShowMe() cout Name t Sex t Age endl; ;,class Student:private Person /私有继承 int Number; /学号 char ClassName10; /班级 public: void RegisterStu(char *name, int sex, char age, int number, char *classname) Register(name, sex, age); Age=age; Number = number; strcpy(ClassName, classname); void ShowStu() ShowMe(); cout Number t ClassName endl; ;,24,派生类的继承方式和访问属性(续),private(私有继承) int main() Student stu; stu.RegisterStu(“张弓长“, m,18, 85071011, “计算机51“); stu.Age=18; stu.ShowStu(); stu.ShowMe(); /成为派生类的私有成员 return 0; ,25,在派生类中 不管什么继承方式,只能访问父类的公有成员和保护成员,不能访问父类的私有成员。 在派生类外,通过派生类对象 不管什么继承方式,只能访问公有成员(包括新增的和继承的),不能访问保护成员和私有成员(包括新增的和继承的)。,小结,26,class Base private: int a ; void f() couta; protected: int b ; void g() coutb; public: int c ; void k() coutc; ;,class Sub : public Base public: void test() a = 1 ; f() ; b = 2 ; g() ; c = 3 ; k() ; ;,void main() Sub d ; d.a = 1 ; d.f() ; d.b = 2 ; d.g() ; d.c = 3 ; d.k() ; ,练习1,27,class Base private: int a ; void f() couta; protected: int b ; void g() coutb; public: int c ; void k() coutc; ;,class Sub : protected Base public: void test() a = 1 ; f() ; b = 2 ; g() ; c = 3 ; k() ; ;,void main() Sub d ; d.a = 1 ; d.f() ; d.b = 2 ; d.g() ; d.c = 3 ; d.k() ; ,练习2,28,class Base private: int a ; void f() couta; protected: int b ; void g() coutb; public: int c ; void k() coutc; ;,class Sub : private Base public: void test() a = 1 ; f() ; b = 2 ; g() ; c = 3 ; k() ; ;,int main() Sub d ; d.a = 1 ; d.f() ; d.b = 2 ; d.g() ; d.c = 3 ; d.k() ; ,练习3,protected继承 与private继承的区别?,29,class A int myPrivate; protected: int myProtected; public: int myPublic; ; class B1:protected A void SetNum()myProtected=1;myPublic=1; ; class C1:public B1 void SetNum()myProtected=1;myPublic=1; ; class B2:private A void SetNum()myProtected=1;myPublic=1; ; class C2:public B2 void SetNum()myProtected=1;myPublic=1; ;,多层派生(1),30,不管有多少层派生,对某一个派生类来说 派生类中继承成员的访问属性:只由其在直接父类的访问属性和继承方式确定。 派生类中新增成员的访问属性:由其在类中的定义确定。,多层派生(2),31,基类的构造函数和析构函数都不能被继承,派生类中需要声明自己的构造函数和析构函数。 在设计派生类的构造函数时候,不仅要考虑派生类所新增的数据成员初始化,还要考虑基类的数据成员初始化。 声明构造函数时,除了对本类中新增成员进行初始化外,对继承来的基类成员的初始化,需用初始化列表调用基类构造函数完成。,派生类的构造函数(1),32,派生类构造函数的一般形式 派生类名(总参数表):基类名1(参数表1),基类名2(参数表2),对象成员名1(对象参数表1),对象成员名2(对象参数表2), 派生类中新增数据成员的初始化 有三种数据要考虑初始化: 基类中的数据成员初始化基类构造函数 本类中的对象成员初始化相应类的构造函数 本类中新增的数据成员函数体,派生类的构造函数(2),33,派生类构造函数说明: 总参数表:包括派生类中新增加的数据成员,以及全部基类和全部对象成员的所有参数。 如果基类中没有定义构造函数,或定义了没有参数的构造函数(默认构造函数),则在初始化列表中可略去“基类名(参数表)”。此时,若派生类及对象成员都不需初始化,则可以不定义派生类的构造函数。 如果基类中定义的构造函数带参数,则必须定义派生类构造函数,并通过初始化列表传递参数。 如果基类中既定义无参的构造函数,又定义了有参的构造函数,在定义派生类构造函数时,既可以包含基类构造函数及其参数,也可以不包含基类构造函数。,派生类的构造函数(3),34,派生类的构造函数(4),派生类默认构造函数 如果没有定义构造函数,则会调用默认的无参构造函数。 派生类的默认构造函数首先会调用父类的无参构造函数(如果父类定义了有参构造函数,又没有重载无参构造函数,则编译错误)。 如果父类的上面还有父类,则依次类推。,35,派生类构造函数执行次序: 调用基类构造函数,调用顺序按照被声明时的顺序 调用对象成员构造函数,调用顺序按照被声明时的顺序 执行派生类构造函数体,派生类的构造函数(5),36,析构函数也不被继承,派生类需自行声明。 声明方法与一般(无继承关系时)类的析构函数相同。 不需要显式地调用基类的析构函数,系统会自动隐式调用。 析构函数的调用次序与构造函数相反。,派生类的析构函数,调用构造函数的次序:,基类,对象成员,派生类,基类,对象成员,派生类,调用析构函数的次序:,37,#include #include class Person char Name10; /姓名 int Age; /年龄 public: Person(char* name,int age) strcpy(Name, name); Age = age; cout“constructor of person“Nameendl; Person() cout“deconstrutor of person“Nameendl; ;,class Student : public Person char ClassName10; /班级 Person Monitor; /班长,对象成员 public: Student(char *name, int age, char *classname, char *name1, int age1):Person(name, age) , Monitor(name1, age1) strcpy(ClassName, classname); cout“constructor of Student “endl; Student() cout“deconstrucor of Student “endl; ; int main() Student stu(“张弓长“,18,“计算机51“,“李木子“,20); return 0; ,38,#include #include using namespace std; class Student public: Student(int n, string nam) num=n; name=nam; void display() cout“num:“numendl; cout“name:“nameendl; protected: int num; string name; ;,class Student1:public Student public: Student1(int n, string nam,int n1, string nam1,int a, string ad): Student(n,nam),monitor(n1,nam1) age=a; addr=ad; void show() cout“This student is:“endl; display(); cout“age:“ageendl; cout“address:“addrendl; void show_monitor() coutendl“Class monitor is:“ endl; monitor.display(); private: Student monitor; int age; string addr; ;,int main() Student1 stud1(10010,“Wang-li“, 1001,“Liu-xiang“,19,“115 Beijing Road,Shanghai“); stud1.show(); stud1.show_monitor(); return 0; ,39,多层派生时的构造函数,#include #include using namespace std; class Student public: Student(int n, string nam) num=n; name=nam; cout“constructor of Student “; cout“num:“num“ name:“ nameendl; protected: int num; string name; ; class Student1:public Student public: Student1(int n, string nam, int a): Student(n,nam) age=a; cout“constructor of Student1 “ “age:“ageendl; private: int age; ;,class Student2:public Student1 public: Student2(int n, string nam,int a,int s) :Student1(n,nam,a) score=s; cout“constructor of Student2 “ “score:“scoreendl; private: int score; ; int main() Student2 stud(10010,“Li“,17,89); return 0; ,40,多层派生时的构造函数(续),先初始化Student的数据成员num和name 再初始化Student1的数据成员age 最后再初始化Student2的数据成员score 有多层派生时,每一层派生类的构造函数,不需要列出其上面所有各层派生类的构造函数,只需写出直接父类的构造函数即可。,41,派生类的拷贝构造函数,拷贝构造与构造函数的方式类似: 派生类若自定义拷贝构造函数,则派生类对象在拷贝创建时先调用父类的拷贝构造函数,再调用派生类拷贝构造函数完成自己的拷贝。 若基类没有定义拷贝构造函数,则派生类对象在拷贝创建中调用基类默认的拷贝构造函数。 派生类若没有定义拷贝构造函数,则派生类对象在拷贝创建时先调用父类的默认拷贝构造函数,再调用派生类默认拷贝构造函数。,42,继承与派生结构: 单派生:一个基类派生出一个派生类 多派生:一个基类派生出多个不同的派生类 多层派生:派生类又作为基类,继续派生新的类 单继承:派生类只从一个基类派生 多(重)继承:派生类从多个基类派生,继承与派生结构,43,多派生,#include #include using namespace std; class Person protected: char Name10; char Sex; int Age; public: void Register(char *name,int age,char sex) strcpy(Name, name); Sex= (sex=m? m: f ); Age = age; void ShowMe() cout“ 姓名:“Nameendl; cout“ 性别:“(Sex=m?“男“:“女“)endl; cout“ 年龄:“Ageendl; ;,class Teacher : public Person char Dept20; int Salary; public: Teacher(char *name,int age,char sex,char *dept, int salary); void ShowMe() Person:ShowMe(); cout“ 工作单位:“Deptendl; cout“ 月薪:“Salaryendlendl; ; Teacher:Teacher(char *name,int age,char sex,char *dept,int salary) Register(name,age,sex); strcpy(Dept, dept); Salary = salary; ,44,多派生(续),class Student : public Person char ID12; char Class12; public: Student(char *name,int age,char sex, char *id,char *classid); void ShowMe() cout“ 学号:“IDendl; Person:ShowMe(); cout“ 班级:“Class“n“; ; Student:Student(char *name,int age,char sex,char *id,char *classid) Register(name,age,sex); strcpy(ID, id); strcpy(Class, classid); ,int main() Teacher teach1(“章立早“,38,m,“计算机学院“,2300); Student std1(“李木子“,22,f,“02035003“,“信管01“); teach1.ShowMe(); std1.ShowMe(); return 0; ,45,单继承,/ Point.h文件 Point类的声明 #ifndef POINT_H #define POINT_H class Point int x, y;/点的x和y坐标 public: Point( int = 0, int = 0 ); void SetPoint( int, int ); / 设置坐标 int GetX() return x; / 取x坐标 int GetY() return y; / 取y坐标 void Print(); /输出点的坐标 ; #endif,/ Point.cpp文件 Point类的成员函数定义 #include using namespace std; #include “point.h“ Point:Point( int a, int b ) SetPoint( a, b ); void Point:SetPoint( int a, int b ) x = a; y = b; void Point:Print() cout x “, “ y ; ,46,单继承(续),/ Circle.h文件 Circle类的声明 #ifndef CIRCLE_H #define CIRCLE_H #include using namespace std; #include “point.h“ class Circle : public Point double radius; public: Circle(int x = 0, int y = 0 , double r = 0.0); void SetRadius( double ); /设置半径 double GetRadius();/取半径 double Area();/计算面积 void Print();/输出圆心坐标和半径 ; #endif,/ Circle.cpp文件 Circle类的成员函数定义 #include using namespace std; #include “circle.h“ Circle:Circle(int a,int b,double r): Point(a,b) SetRadius( r ); void Circle:SetRadius( double r ) radius = ( r = 0 ? r : 0 ); double Circle:GetRadius() return radius; double Circle:Area() return 3.14159 * radius * radius; void Circle:Print() cout “Center = “; Point:Print(); cout “; Radius = “ radius endl; ,47,单继承(续),/ Example11-5.cpp文件 #include using namespace std; #include “point.h“ #include “circle.h“ int main() Point p(30,50); Circle c(120,80,10.0); cout “Point p: “; p.Print(); cout “nCircle c: “; c.Print(); cout “The centre of circle c: “; c.Point:Print(); cout “nThe area of circle c: “ c.Area() endl; return 0; ,48,多继承时派生类的声明 class 派生类名 : 继承方式1 基类名1, 继承方式2 基类名2, ; 注意:每个继承方式,仅限制紧随其后的基类的继承。,多继承的声明,49,构造函数的调用次序: 调用基类构造函数,调用顺序按照它们被继承时声明的顺序(从左到右)。 调用对象成员的构造函数,调用顺序按照它们在类中声明的顺序。 执行派生类的构造函数体。,多继承的构造函数与析构函数,50,多继承,/ base1.h文件 #ifndef BASE1_H #define BASE1_H class Base1 int value; public: Base1( int x ) value = x; int getData() const return value; ; #endif,/ base2.h文件 #ifndef BASE2_H #define BASE2_H class Base2 char letter; public: Base2( char c ) letter = c; char getData() const return letter; ; #endif,51,多继承(续),/ derived.h文件 #ifndef DERIVED_H #define DERIVED_H #include “base1.h“ #include “base2.h“ / 多继承 class Derived : public Base1, public Base2 double real; / 派生类私有的数据成员 public: Derived( int, char, double ); double getReal() const; void Output(); ; #endif,/ derived.cpp文件 #include using namespace std; #include “derived.h“ Derived:Derived( int i, char c, double f ): Base1( i ), Base2( c ), real ( f ) double Derived:getReal() const return real; void Derived:Output() cout “Integer: “ Base1:getData() “nCharacter: “ Base2:getData() “nReal number: “ real endl; ,52,/ Example11-7.cpp文件多重派生 #include using namespace std; #include “base1.h“ #include “base2.h“ #include “derived.h“ int main() Base1 b1( 10 ), *base1Ptr = 0; Base2 b2( Z ), *base2Ptr = 0; Derived d( 7, A, 3.5 ); /对象输出各自的数据成员 cout “Object b1 contains integer “ b1.getData() “nObject b2 contains character “ b2.getData() “nObject d contains:n“; d.Output(); /派生类对象对基类成员函数的访问 cout “Data members of Derived can be“ “ accessed individually:“;,coutgetData() yields “ getData() getData() yields “ getData() endl; return 0; ,53,赋值兼容规则,在派生类对象和基类对象之间赋值时需要注意赋值的方向,赋值操作应满足赋值兼容原则(向上兼容): 基类指针可以指向派生类对象。 可以把派生类对象赋值给基类对象。 派生类对象可以初始化基类对象的引用。 通过基类对象名、指针只能使用派生类从基类继承的成员(不能使用派生类新增的成员),54,赋值兼容规则举例(1),class A int x; public: void setX(int m) x=m; void printX() coutxn; ; class B : public A int y; public: void setY(int m) y=m; void printY() coutyn; ;,void main() A a; a.setX(2); a.printX(); B b; b.setX(3); b.setY(4); b.printX(); b.printY(); A c=b; c.printX(); ,55,赋值兼容规则举例(2),#include using namespace std; class Pet /基类 public: void Speak() cout“How does a pet speak ?“endl; ; class Cat : public Pet /派生类 public: void Speak() cout“miao!miao!“endl; ; class Dog : public Pet /派生类 public: void Speak() cout“wang!wang!“endl; ;,int main() Pet obj,*p1; /基类对象指针p1, 基类对象obj Dog dog1; Cat cat1; obj = dog1; /用Dog类对象给Pet类对象赋值 obj.Speak(); p1 = ,56,class A public: int a; void display(); ; class B public: int a; void display(); ;,class C: public A, public B public: int a; void show(); ; void main() C c1; c1.a=3; /执行哪一个? c1.display();/执行哪一个? ,两个基类有同名成员,57,两个基类有同名成员(续),如何解决这种二义性?,58,二义性问题(1),在多继承时,若基类与派生类之间,或基类之间出现同名成员,将出现访问时的二义性(不确定性)。 当同一个基类被同一个派生类间接继承多次的时候,将在该派生类中产生该基类的多个副本。此时访问该基类中的成员,将产生二义性。,59,二义性问题(2),解决二义性的方法 同名覆盖(隐藏)原则 如果派生类与基类之间出现同名成员,这时系统自动用派生类的成员名覆盖(隐藏)基类成员名,派生类成员名优先。 类名限定法 不同基类之间出现同名成员,使用基类名来显式指定成员 基类名:数据成员名 基类名:成员函数名(参数表);,60,class A public: int a; void display(); ; class B public: int a; void display(); ;,clas

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论