C++实用教程[郑阿奇主编]ppt课件_第1页
C++实用教程[郑阿奇主编]ppt课件_第2页
C++实用教程[郑阿奇主编]ppt课件_第3页
C++实用教程[郑阿奇主编]ppt课件_第4页
C++实用教程[郑阿奇主编]ppt课件_第5页
已阅读5页,还剩50页未读 继续免费阅读

下载本文档

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

文档简介

1、.,第12章 继承和派生,.,12.1 继承和派生概述,12.1.1 继承的概念 1. 继承和概括 继承(Inheritance),是指一个事物可以继承其父辈全部或部分特性,同时本身还有自己的特性。 2. 类继承相关概念 在C+中,当一个新类从一个已定义的类中派生后,新类不仅继承了原有类的属性和方法,并且还拥有自己新的属性和方法,称为类的继承和派生。被继承的类称为基类(Base class)或超类(Super class)(又称父类),在基类或父类上建立的新类称为派生类(Derived class)或子类(Sub class)。,.,3. 类层次关系的描述方法上述父类和子类的关系称为类层次或继

2、承关系。在类设计时,常常将这些关系用树来描述。例如,下图就是用树来描述学校人员类的层次关系。,.,12.1.2 继承的特性,在C+中,类的继承具有下列特性: (1)单向性。 (2)传递性。 (3)可重用性。 12.1.3 派生类的定义 在C+中,一个派生类的定义可按下列格式: class : , , ;,.,12.2 继承方式,C+继承方式有三种:public(公有)、private(私有)及protected(保护) 12.2.1 公有继承 公有继承(public)方式具有下列特点: (1)在派生类中,基类的公有成员、保护成员和私有成员的访问属性保持不变。 (2)派生类对象只能访问派生类和基

3、类的公有(public)成员。,.,例Ex_PublicDerived 派生类的公有继承示例。,#include #include using namespace std; class CPerson public: CPerson(char *name, int age, char sex = M) strncpy(this-name, name, 20); this-age = age;this-sex = sex; void SetNameAndSex( char *name, char sex = M) / 更改姓名和性别 strncpy(this-name, name, 20);th

4、is-sex = sex; protected:,.,void SetAge(int age) this-age = age; void ShowInfo()/ 显示信息 cout姓名:nameendl; cout性别:(sex=M?男:女)endl; cout年龄:ageendl; private: charname20;/ 姓名 charsex;/ 性别 intage;/ 年龄 ; class CStudent :public CPerson,., public: CStudent(char *name, char *no, int age, char sex = M) :CPerson(

5、name, age, sex)/ 调用基类构造函数进行初始化 strncpy(this-stuno, no, 20); void SetScore( float s1, float s2, float s3 ) score0 = s1;score1 = s2;score2 = s3; total = s1 + s2 + s3;ave = total / (float)3.0; void SetNoAndAge(char *no, int age) strncpy(this-stuno, no, 20);this-SetAge( age ); void ShowAll() ShowInfo();

6、/ 调用基类的成员函数 cout学号:stunoendl; cout三门成绩:score0tscore1tscore2endl; cout总成绩和平均分:totaltaveendl; ,.,private: charstuno20;/ 学号 floatscore3,ave, total;/ 三门成绩、平均分和总分 ; int main() CStudent one(LiMing, 21050101, 19 );/ A one.SetScore( 90, 80, 84);/ B one.ShowAll();/ 调用派生类的公有成员函数 one.SetNameAndSex(WangFang, W)

7、; / 调用基类的公有成员函数 one.SetNoAndAge(21050102, 18 ); / 调用派生类的公有成员函数 one.ShowAll();/ 调用派生类的公有成员函数 return 0; ,.,程序运行结果如下:,.,12.2.2 私有继承,私有继承(private)方式具有下列特点: (1)在派生类中,基类的公有成员、保护成员和私有成员的访问属性都将变成私有(private),且基类的私有成员在派生类中被隐藏。 (2)由于基类的所有成员在派生类中都变成私有的,因此基类的所有成员在派生类的子类中都是不可见的。 (3)派生类对象只能访问派生类的公有成员,不能访问基类的任何成员。,

8、.,例Ex_PrivateDerived 派生类的私有继承示例。,#include #include using namespace std; class CPerson public: CPerson(char *name, int age, char sex = M) strncpy(this-name, name, 20); this-age = age;this-sex = sex; void SetNameAndSex( char *name, char sex = M) / 更改姓名和性别 strncpy(this-name, name, 20);this-sex = sex; p

9、rotected:,.,void SetAge(int age) this-age = age; void ShowInfo()/ 显示信息 cout姓名:nameendl; cout性别:(sex=M?男:女)endl; cout年龄:ageendl; private: charname20;/ 姓名 charsex;/ 性别 intage;/ 年龄 ; class CStudent :private CPerson public: CStudent(char *name, char *no, int age, char sex = M) :CPerson(name, age, sex) /

10、 调用基类公有构造函数进行初始化,., strncpy(this-stuno, no, 20); public: void SetScore( float s1, float s2, float s3 ) score0 = s1;score1 = s2;score2 = s3; total = s1 + s2 + s3;ave = total / (float)3.0; void SetNoAndAge(char *no, int age) strncpy(this-stuno, no, 20);this-SetAge( age ); void ShowAll() ShowInfo();/ 调

11、用基类的保护成员函数 cout学号:stunoendl; cout三门成绩:score0tscore1tscore2endl; cout总成绩和平均分:totaltaveendl; / 修改的代码,.,void SetNameAndSex( char *name, char sex = M)/ 更改姓名和性别 CPerson:SetNameAndSex(name, sex); / 调用基类的公有成员函数 private: charstuno20;/ 学号 floatscore3,ave, total; / 三门成绩、平均分和总分 ; int main() CStudent one(LiMing

12、, 21050101, 19 ); one.SetScore( 90, 80, 84); one.ShowAll(); one.SetNameAndSex(WangFang, W); one.SetNoAndAge(21050102, 18 ); one.ShowAll(); return 0; 程序运行结果同前。,.,12.2.3 保护继承,保护继承(protected)方式具有下列特点: (1)在派生类中,基类的公有成员、保护成员的访问属性都将变成保护的。 (2)同私有继承一样,在保护继承方式下,派生类中仍可访问基类的公有成员和保护成员。,.,12.3 派生类的构造和析构 12.3.1 构

13、造和析构次 1. 单继承 如图12.2(a)所示,A类是B类的基类,B类又是C类的基类,它们是多层单继承方式 其代码如下:,.,class A public: A()cout执行A的构造函数endl; A()cout执行A的析构函数endl; ; class B: public A public: B()cout执行B的构造函数endl; B()cout执行B的析构函数endl; ; class C: public B,., public: C()cout执行C的构造函数endl; C()cout执行C的析构函数endl; ; int main() C c; return 0; 程序运行结果如

14、下,.,2. 多继承如图12.2(b)所示,类A和类B是C类的基类,它们是多继承方式,其代码如下:,class A public: A()cout执行A的构造函数endl; A()cout执行A的析构函数endl; ; class B public: B()cout执行B的构造函数endl; B()cout执行B的析构函数endl; ; class C: public B, public A,., public: C()cout执行C的构造函数endl; C()cout执行C的析构函数endl; ; int main() C c; return 0; 程序运行结果如下: 执行B的构造函数 执行

15、A的构造函数 执行C的构造函数 执行C的构造函数 执行A的构造函数 执行B的构造函数,.,12.3.2 派生类数据成员初始化,一个派生类的构造函数的定义可有下列格式:(形参表) :基类1(参数表), 基类2(参数表), , 基类n(参数表), 对象成员1(参数表), 对象成员2(参数表), , 对象成员n(参数表) ,例如,一个长方体类CCuboid,它从基类矩形类CRect派生而来。基类CRect的数据成员是两个CPoint类对象ptLT和ptRB,分别表示矩形的左上角点和右下角点的位置。派生类CCuboid自身的数据成员有表示高度的fHeight,表示底面中点位置的CPoint对象ptCe

16、nter,如右图所示。具体程序如下。,.,例Ex_ClassDerived 派生类的构造和析构示例。,#include using namespace std; class CPoint public: CPoint( int x = 0, int y = 0)/ C xPos = x;yPos = y; coutCPoint构造函数endl; void ShowPos(bool isEnd = false) coutpos(xPos, yPos); if (isEnd)coutendl; private: int xPos, yPos; ;,.,class CRect public: CRe

17、ct( int x1 = 0, int y1 = 0, int x2 = 0, int y2 = 0)/ B : ptLT(x1, y1), ptRB(x2, y2) coutCRect构造函数endl; void ShowPos() ptLT.ShowPos(); cout, ; ptRB.ShowPos(true); private: CPoint ptLT, ptRB; ;,.,class CCuboid: public CRect public: CCuboid( int x1, int y1, int x2, int y2, int height )/ A : CRect(x1, y

18、1, x2, y2), ptCenter(x1+x2)/2, (y1+y2)/2), fHeight(height) coutCCuboid构造函数endl; void ShowAll() cout矩形的角点为:;CRect:ShowPos(); cout底面矩形的中点为:;ptCenter.ShowPos(true); cout高为:fHeightendl; ,.,private: CPointptCenter; floatfHeight; ; int main() CCuboid one( 5, 5, 30, 30, 50); one.ShowAll(); return 0; 程序运行结果

19、如下:,.,12.4 二义性和虚基类,12.4.1 二义性概述 一般来说,在派生类中对基类成员的访问应该是唯一的。但是多继承或多层继承可能造成对基类中某成员的访问出现不唯一的情况,这种情况称为基类成员调用的二义性。 二义性出现的情况可以有下列两种。 1. 同名成员来源于不同的基类 例Ex_Conflict1 同名成员来源于不同的基类,.,#include using namespace std; class A public: int x; A(int a = 0) x = a; ; class B public: int x; B( int a = 0, int b = 0) x = a;

20、; class C : public B, public A,., public: int z; C(int a, int b, int c) :A(a), B(b) z = c; void print() coutx = xendl;/ 编译出错的地方 coutz = zendl; ; int main() C c1(100,200,300); c1.print(); return 0; ,.,程序中,派生类C同时继承了A和B这两个基类,由于基类A和基类B都有数据成员x,当编译到“coutx = xendl;”语句时,无法确定成员x是来自基类A还是来自基类B,因此产生了二义性,从而出现编译错

21、误。解决这个问题的简单方法是使用域作用运算符“:”来消除二义性,即将print函数实现代码改为:,void print() coutA:x = A:xendl; coutB:x = B:xendl; coutz = zendl; 重新运行的结果如下,.,2. 同名成员来源于同一个基类,例Ex_Conflict2 同名成员来源于同一个基类。 #include using namespace std; class A public: int x; A(int a = 0) x = a; ; class B1 : public A public: int y1; B1( int a = 0, int

22、 b = 0) :A(b) y1 = a; ;,.,class B2 : public A public: int y2; B2( int a = 0, int b = 0) :A(b) y2 = a; ; class C : public B1, public B2 public: int z; C(int a, int b, int d, int e, int m) :B1(a,b), B2(d,e) z = m; ,.,void print() coutx = xendl;/ 编译出错的地方 couty1 = y1, y2 = y2endl; coutz = zendl; ; int m

23、ain() C c1(100,200,300,400,500); c1.print(); return 0; 程序中,B1类和B2类都是从基类A继承的派生类,这时在继承B1和B2的派生类C中就有两个基类A的拷贝。当编译器编译到“coutx = xendl;”语句时,因无法确定成员x是从类B1中继承来的,还是从类B2继承来的,因此产生二义性,从而出现了编译错误。 解决这个问题仍可使用前面的方法,即使用域作用运算符“:”通过指定基类来消除二义性。例如,可将print函数实现代码改写为,.,void print() coutB1:x = B1:xendl; coutB2:x = B2:xendl;

24、couty1 = y1, y2 = y2endl; coutz = zendl; 重新运行后的结果如下:,.,12.4.2 二义性解决方法,(1)当派生类和其基类中都有一个成员X时,在派生类中访问的X就是派生类的成员X,这是C+中类的局部优先原则。 (2)若A类是B类的基类,B类是C类的基类,当A类和B类都有一个成员X时,则在子类C中访问的X是B类的成员,这是C+中类的最近优先原则。 对于出现二义性的第1种情况,指定作用域是最好的解决方法。但对于第2种情况,指定作用域虽是一种解决方法,但不是最好的办法。因为在派生类C中总有两个基类A的拷贝,不仅多占用内存,而且效率也不高。为此在实际应用中多采用

25、虚基类的形式来解决。,.,12.4.3 虚基类和虚继承,1. 虚基类的定义 虚基类不是指基类是虚的,而是指在派生类中指定的基类是虚继承方式,即使用下列格式定义派生类的继承方式: class : virtual ; 例Ex_VirtualBase 虚基类的使用示例。,.,#include using namespace std; class A public: int x; A(int a = 0) x = a; ; class B1 : virtual public A/ 声明虚继承 public: int y1; B1( int a = 0, int b = 0) :A(b) y1 = a;

26、 void print(void) coutB1: x = x, y1 = y1endl; ;,.,class B2 : virtual public A/ 声明虚继承 public: int y2; B2( int a = 0, int b = 0) :A(b) y2 = a; void print(void) coutB2: x = x, y2 = y2endl; ; class C : public B1, public B2 public: int z; C(int a, int b, int d, int e, int m) :B1(a,b), B2(d,e) z = m; ,.,v

27、oid print() B1:print();B2:print(); coutz = zendl; ; int main() C c1(100,200,300,400,500);c1.print(); c1.x = 400;c1.print(); return 0; 程序运行结果如下:,.,2. 虚基类的实质 在上述示例中,类A、B1、B2和C的层次关系可用图12.5来表示,图12.5 类的层次关系,.,12.5 兼容,兼容是指在公有派生情况下,一个派生类对象可以赋给基类对象,这种情况又称为赋值兼容,或称类型自动转换。 12.5.1 赋值兼容规则 简单地讲,对于公有派生类来说,可以将派生类的对

28、象直接赋给其基类对象,反之却不可以。 12.5.2 赋值兼容机理 例Ex_CastTest 派生类赋值兼容测试示例。,.,#include #include using namespace std; class CA public: CA(int x = 0) a = x; int getA() return a; private: int a; ; class CB public: CB(int x = 0) b = x; int getB() return b; private: int b; ; class CC: public CB, public CA,., public: CC(

29、int y = 0) c = y; int getC() return c; private: int c; ; int main() CC *c = new CC(5); coutgetC()getB()getA()getC()getB()getA()endl; delete c; return 0; 程序运行结果如下:,.,Ex_CastOther 派生类赋值兼容其他情况示例。,#include #include using namespace std; class CA public: CA(int x = 0) a = x; int getA() return a; void Show

30、Addr() coutCA对象的地址:(unsigned)thisendl; coutta的地址:(unsigned) class CB ,.,public: CB(int x = 0) b = x; int getB() return b; void ShowAddr() coutCB对象的地址:(unsigned)thisendl; couttb的地址:(unsigned) ,.,private: int c; ; int main() CC c(5);/ c对象中的数据成员c为5 coutShowAddr(); cout- CB ,.,程序运行结果如下:,.,12.6 综合应用实例,12

31、.6.1 类间关系 1. 继承关系 2. 组合关系 3. 共享关系,.,12.6.2 设计实例,例Ex_Multi12 综合应用实例 #include #include using namespace std; class CPerson public: CPerson() CPerson(char *name, int age, char sex = M) strncpy(this-name, name, 20); this-age = age;this-sex = sex; ,.,void ShowInfo()/ 显示信息 cout姓名:nameendl; cout性别:(sex=M?男:

32、女)endl; cout年龄:ageendl; private: charname20;/ 姓名 charsex;/ 性别 intage;/ 年龄 ; class CStudent :virtual public CPerson public: CStudent(char *name, int age, char sex = M) :CPerson(name, age, sex)/ 调用基类构造函数进行初始化 ,.,void SetData( char *strname, char *stuno, float s1, float s2, float s3 ) strncpy(this-clas

33、sname, strname, 20); strncpy(this-stuno, stuno, 20); score0 = s1;score1 = s2;score2 = s3; total = s1 + s2 + s3;ave = total / (float)3.0; void ShowInfo() cout班级:classnameendl; cout学号:stunoendl; cout三门成绩:score0tscore1tscore2endl; cout总成绩和平均分:totaltaveendl; private: charclassname20;/ 班级 charstuno20;/ 学号 floatscore3,ave, total;/ 三门成绩、平均分和总分 ;,.,class CTeacher :virtu

温馨提示

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

评论

0/150

提交评论