C++实用教程郑阿奇主编12[基本功课].ppt

上传人:scccc 文档编号:11891208 上传时间:2021-10-16 格式:PPT 页数:55 大小:776KB
返回 下载 相关 举报
C++实用教程郑阿奇主编12[基本功课].ppt_第1页
第1页 / 共55页
C++实用教程郑阿奇主编12[基本功课].ppt_第2页
第2页 / 共55页
C++实用教程郑阿奇主编12[基本功课].ppt_第3页
第3页 / 共55页
C++实用教程郑阿奇主编12[基本功课].ppt_第4页
第4页 / 共55页
C++实用教程郑阿奇主编12[基本功课].ppt_第5页
第5页 / 共55页
点击查看更多>>
资源描述

《C++实用教程郑阿奇主编12[基本功课].ppt》由会员分享,可在线阅读,更多相关《C++实用教程郑阿奇主编12[基本功课].ppt(55页珍藏版)》请在三一文库上搜索。

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

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

3、 (2)派生类对象只能访问派生类和基类的公有(public)成员。,5,教育育人,例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(

4、this-name, name, 20);this-sex = sex; protected:,6,教育育人,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,7,教育育人, public: CStudent(char *name, char *no,

5、 int age, char sex = M) :CPerson(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(

6、age ); void ShowAll() ShowInfo();/ 调用基类的成员函数 cout学号:stunoendl; cout三门成绩:score0tscore1tscore2endl; cout总成绩和平均分:totaltaveendl; ,8,教育育人,rivate: charstuno20;/ 学号 floatscore3,ave, total;/ 三门成绩、平均分和总分 ; int main() CStudent one(LiMing, 21050101, 19 );/ A one.SetScore( 90, 80, 84);/ B one.ShowAll();/ 调用派生类的

7、公有成员函数 one.SetNameAndSex(WangFang, W); / 调用基类的公有成员函数 one.SetNoAndAge(21050102, 18 ); / 调用派生类的公有成员函数 one.ShowAll();/ 调用派生类的公有成员函数 return 0; ,9,教育育人,程序运行结果如下:,10,教育育人,12.2.2 私有继承,私有继承(private)方式具有下列特点: (1)在派生类中,基类的公有成员、保护成员和私有成员的访问属性都将变成私有(private),且基类的私有成员在派生类中被隐藏。 (2)由于基类的所有成员在派生类中都变成私有的,因此基类的所有成员在派

8、生类的子类中都是不可见的。 (3)派生类对象只能访问派生类的公有成员,不能访问基类的任何成员。,11,教育育人,例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) /

9、更改姓名和性别 strncpy(this-name, name, 20);this-sex = sex; protected:,12,教育育人,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,

10、 char *no, int age, char sex = M) :CPerson(name, age, sex) / 调用基类公有构造函数进行初始化,13,教育育人, 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(thi

11、s-stuno, no, 20);this-SetAge( age ); void ShowAll() ShowInfo();/ 调用基类的保护成员函数 cout学号:stunoendl; cout三门成绩:score0tscore1tscore2endl; cout总成绩和平均分:totaltaveendl; / 修改的代码,14,教育育人,void SetNameAndSex( char *name, char sex = M)/ 更改姓名和性别 CPerson:SetNameAndSex(name, sex); / 调用基类的公有成员函数 private: charstuno20;/ 学

12、号 floatscore3,ave, total; / 三门成绩、平均分和总分 ; int main() CStudent one(LiMing, 21050101, 19 ); one.SetScore( 90, 80, 84); one.ShowAll(); one.SetNameAndSex(WangFang, W); one.SetNoAndAge(21050102, 18 ); one.ShowAll(); return 0; 程序运行结果同前。,15,教育育人,12.2.3 保护继承,保护继承(protected)方式具有下列特点: (1)在派生类中,基类的公有成员、保护成员的访问

13、属性都将变成保护的。 (2)同私有继承一样,在保护继承方式下,派生类中仍可访问基类的公有成员和保护成员。,16,教育育人,12.3 派生类的构造和析构 12.3.1 构造和析构次 1. 单继承 如图12.2(a)所示,A类是B类的基类,B类又是C类的基类,它们是多层单继承方式 其代码如下:,17,教育育人,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

14、B,18,教育育人, public: C()cout执行C的构造函数endl; C()cout执行C的析构函数endl; ; int main() C c; return 0; 程序运行结果如下,19,教育育人,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,

15、20,教育育人, public: C()cout执行C的构造函数endl; C()cout执行C的析构函数endl; ; int main() C c; return 0; 程序运行结果如下: 执行B的构造函数 执行A的构造函数 执行C的构造函数 执行C的构造函数 执行A的构造函数 执行B的构造函数,21,教育育人,12.3.2 派生类数据成员初始化,一个派生类的构造函数的定义可有下列格式:(形参表) :基类1(参数表), 基类2(参数表), , 基类n(参数表), 对象成员1(参数表), 对象成员2(参数表), , 对象成员n(参数表) ,例如,一个长方体类CCuboid,它从基类矩形类CR

16、ect派生而来。基类CRect的数据成员是两个CPoint类对象ptLT和ptRB,分别表示矩形的左上角点和右下角点的位置。派生类CCuboid自身的数据成员有表示高度的fHeight,表示底面中点位置的CPoint对象ptCenter,如右图所示。具体程序如下。,22,教育育人,例Ex_ClassDerived 派生类的构造和析构示例。,#include using namespace std; class CPoint public: CPoint( int x = 0, int y = 0)/ C xPos = x;yPos = y; coutCPoint构造函数endl; void S

17、howPos(bool isEnd = false) coutpos(xPos, yPos); if (isEnd)coutendl; private: int xPos, yPos; ;,23,教育育人,class CRect public: CRect( 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: CPo

18、int ptLT, ptRB; ;,24,教育育人,class CCuboid: public CRect public: CCuboid( int x1, int y1, int x2, int y2, int height )/ A : CRect(x1, y1, x2, y2), ptCenter(x1+x2)/2, (y1+y2)/2), fHeight(height) coutCCuboid构造函数endl; void ShowAll() cout矩形的角点为:;CRect:ShowPos(); cout底面矩形的中点为:;ptCenter.ShowPos(true); cout高为

19、:fHeightendl; ,25,教育育人,rivate: CPointptCenter; floatfHeight; ; int main() CCuboid one( 5, 5, 30, 30, 50); one.ShowAll(); return 0; 程序运行结果如下:,26,教育育人,12.4 二义性和虚基类,12.4.1 二义性概述 一般来说,在派生类中对基类成员的访问应该是唯一的。但是多继承或多层继承可能造成对基类中某成员的访问出现不唯一的情况,这种情况称为基类成员调用的二义性。 二义性出现的情况可以有下列两种。 1. 同名成员来源于不同的基类 例Ex_Conflict1 同名

20、成员来源于不同的基类,27,教育育人,#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; ; class C : public B, public A,28,教育育人, public: int z; C(int a, int b, int c) :A(a), B(b) z = c; void print() coutx = xendl;/ 编译出错的地方 coutz = zendl; ;

21、int main() C c1(100,200,300); c1.print(); return 0; ,29,教育育人,程序中,派生类C同时继承了A和B这两个基类,由于基类A和基类B都有数据成员x,当编译到“coutx = xendl;”语句时,无法确定成员x是来自基类A还是来自基类B,因此产生了二义性,从而出现编译错误。解决这个问题的简单方法是使用域作用运算符“:”来消除二义性,即将print函数实现代码改为:,void print() coutA:x = A:xendl; coutB:x = B:xendl; coutz = zendl; 重新运行的结果如下,30,教育育人,2. 同名成

22、员来源于同一个基类,例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 b = 0) :A(b) y1 = a; ;,31,教育育人,class B2 : public A public: int y2; B2( int a = 0, int b = 0) :A(b) y2 = a; ; class C : public B1, pu

23、blic B2 public: int z; C(int a, int b, int d, int e, int m) :B1(a,b), B2(d,e) z = m; ,32,教育育人,void print() coutx = xendl;/ 编译出错的地方 couty1 = y1, y2 = y2endl; coutz = zendl; ; int main() C c1(100,200,300,400,500); c1.print(); return 0; 程序中,B1类和B2类都是从基类A继承的派生类,这时在继承B1和B2的派生类C中就有两个基类A的拷贝。当编译器编译到“coutx =

24、 xendl;”语句时,因无法确定成员x是从类B1中继承来的,还是从类B2继承来的,因此产生二义性,从而出现了编译错误。 解决这个问题仍可使用前面的方法,即使用域作用运算符“:”通过指定基类来消除二义性。例如,可将print函数实现代码改写为,33,教育育人,void print() coutB1:x = B1:xendl; coutB2:x = B2:xendl; couty1 = y1, y2 = y2endl; coutz = zendl; 重新运行后的结果如下:,34,教育育人,12.4.2 二义性解决方法,(1)当派生类和其基类中都有一个成员X时,在派生类中访问的X就是派生类的成员X

25、,这是C+中类的局部优先原则。 (2)若A类是B类的基类,B类是C类的基类,当A类和B类都有一个成员X时,则在子类C中访问的X是B类的成员,这是C+中类的最近优先原则。 对于出现二义性的第1种情况,指定作用域是最好的解决方法。但对于第2种情况,指定作用域虽是一种解决方法,但不是最好的办法。因为在派生类C中总有两个基类A的拷贝,不仅多占用内存,而且效率也不高。为此在实际应用中多采用虚基类的形式来解决。,35,教育育人,12.4.3 虚基类和虚继承,1. 虚基类的定义 虚基类不是指基类是虚的,而是指在派生类中指定的基类是虚继承方式,即使用下列格式定义派生类的继承方式: class : virtua

26、l ; 例Ex_VirtualBase 虚基类的使用示例。,36,教育育人,#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; void print(void) coutB1: x = x, y1 = y1endl; ;,37,教育育人,class B2 : virtual public A/ 声明虚继承 public

27、: 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; ,38,教育育人,void print() B1:print();B2:print(); coutz = zendl; ; int main() C c1(100,200,300,400,5

28、00);c1.print(); c1.x = 400;c1.print(); return 0; 程序运行结果如下:,39,教育育人,2. 虚基类的实质 在上述示例中,类A、B1、B2和C的层次关系可用图12.5来表示,图12.5 类的层次关系,40,教育育人,12.5 兼容,兼容是指在公有派生情况下,一个派生类对象可以赋给基类对象,这种情况又称为赋值兼容,或称类型自动转换。 12.5.1 赋值兼容规则 简单地讲,对于公有派生类来说,可以将派生类的对象直接赋给其基类对象,反之却不可以。 12.5.2 赋值兼容机理 例Ex_CastTest 派生类赋值兼容测试示例。,41,教育育人,#inclu

29、de #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,42,教育育人, public: CC( int y = 0) c = y; int getC() return c; private: int c; ; int

30、main() CC *c = new CC(5); coutgetC()getB()getA()getC()getB()getA()endl; delete c; return 0; 程序运行结果如下:,43,教育育人,Ex_CastOther 派生类赋值兼容其他情况示例。,#include #include using namespace std; class CA public: CA(int x = 0) a = x; int getA() return a; void ShowAddr() coutCA对象的地址:(unsigned)thisendl; coutta的地址:(unsig

31、ned) class CB ,44,教育育人,ublic: CB(int x = 0) b = x; int getB() return b; void ShowAddr() coutCB对象的地址:(unsigned)thisendl; couttb的地址:(unsigned) ,45,教育育人,rivate: int c; ; int main() CC c(5);/ c对象中的数据成员c为5 coutShowAddr(); cout- CB ,46,教育育人,程序运行结果如下:,47,教育育人,12.6 综合应用实例,12.6.1 类间关系 1. 继承关系 2. 组合关系 3. 共享关系

32、,48,教育育人,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; ,49,教育育人,void ShowInfo()/ 显示信息 cout姓名:nameendl; cout性别:(sex=M?男:女)endl; cout年龄:ageend

33、l; private: charname20;/ 姓名 charsex;/ 性别 intage;/ 年龄 ; class CStudent :virtual public CPerson public: CStudent(char *name, int age, char sex = M) :CPerson(name, age, sex)/ 调用基类构造函数进行初始化 ,50,教育育人,void SetData( char *strname, char *stuno, float s1, float s2, float s3 ) strncpy(this-classname, strname,

34、 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,a

35、ve, total;/ 三门成绩、平均分和总分 ;,51,教育育人,class CTeacher :virtual public CPerson public: CTeacher(char *name, int age, char sex = M) :CPerson(name, age, sex)/ 调用基类构造函数进行初始化 void SetData( char *title, char *part, int years ) strncpy(this-title, title, 20);strncpy(this-part, part, 20); this-workyears = years;

36、 void ShowInfo() cout职称:titleendl; cout部门:partendl; cout工龄:workyearsendl; ,52,教育育人,rivate: chartitle20;/ 职称 charpart20;/ 部门 intworkyears;/ 工龄 ; class CAssistant : public CTeacher, public CStudent public: CAssistant(char *tname, int tage, char tsex, char *name, int age, char sex = M) :CTeacher(name,

37、age, sex), CStudent(name, age, sex), tutor( tname, tage, tsex ) void SetData( char *duty, char *title, char *part, int years ) strncpy(this-duty, duty, 20); tutor.SetData( title, part, years ); ,53,教育育人,void ShowInfo() cout导师信息:endl; tutor.ShowInfo(); cout职责:dutyendl; private: CTeachertutor; charduty20;/ 职责 ; int main() CAssistant one( DING, 38, M, WANG, 19 ); one.SetData( 批改作业, 教授, 机电学院, 15 ); one.CStudent:SetData( 机电班, 210101, 80, 90, 80 ); one.CTeacher:SetData( 助课, 机电学院, 2 ); one.CTeacher:ShowInfo(); one.CStudent:ShowInfo(); one.ShowInfo(); return 0; ,54,教育育人,程序运行结果如下:,55,教育育人,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 社会民生


经营许可证编号:宁ICP备18001539号-1