资源预览内容
第1页 / 共124页
第2页 / 共124页
第3页 / 共124页
第4页 / 共124页
第5页 / 共124页
第6页 / 共124页
第7页 / 共124页
第8页 / 共124页
第9页 / 共124页
第10页 / 共124页
亲,该文档总共124页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学第第1111章章 继承与派生继承与派生第第1212章章 多态性与虚函数多态性与虚函数第第1313章章 输入输出流输入输出流第第1414章章 C+ C+工具工具第第4 4篇面向对象的程序设计篇面向对象的程序设计墩贫座祈仿岔火湛隅酮喜蝶嫁咯青捕俄纸咖炭芜民傅赐帛邑籍育蕾粤忍瓜第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学第第1111章章 继承与派生继承与派生11.1 11.1 继承与派生的概念继承与派生的概念11.2 11.2 派生类的声明方式派生类的声明方式11.3 11.3 派生类的构成派生类的构成11.4 11.4 派生类成员的访问属性派生类成员的访问属性11.5 11.5 派生类的构造函数和析构函数派生类的构造函数和析构函数11.6 11.6 多重继承多重继承11.7 11.7 基类与派生类的转换基类与派生类的转换11.8 11.8 继承与组合继承与组合11.9 11.9 继承在软件开发中的重要意义继承在软件开发中的重要意义活侍盂枕鼻将思桐捧叭形浴整与赌探窿瞧妻撬功砌虚棘翌袖另穗赞坯彤兽第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学面向对象程序设计有面向对象程序设计有4 4个主要特点个主要特点: : 抽象抽象封装封装继承继承多态性多态性面向对象技术强调软件的可重用性面向对象技术强调软件的可重用性( (software reusability) ) 。C C+语言提供了类的继承机制,解决语言提供了类的继承机制,解决了软件重用问题。了软件重用问题。耍酸汤鹏甲风政钒书钥讫亿缄悯催台旷戈弛酪圾莉腮姻旅蝴咐炽锭盔臆无第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学在在C C+中可重用性是通过继承中可重用性是通过继承(inheritance)这一这一机制来实现的。继承是机制来实现的。继承是C+C+的一个重要组成部分。的一个重要组成部分。在在C C+中,所谓中,所谓“继承继承”就是在一个已存在的类的就是在一个已存在的类的基础上建立一个新的类。基础上建立一个新的类。见图见图11.1示意。示意。11.1 11.1 继承与派生的概念继承与派生的概念耀荆锨播九避驱琢宰凌犁姚行龋雇诉剁靶丘单坏阮继挡并盎服邯辜富膝畜第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学已存在的类已存在的类( (例如例如“马马”)”)称为称为“基类基类(base class)”或或“父类父类( (father class)”)”。新建立的类。新建立的类( (例如例如“公公马马”)”)称为称为“派生类派生类( (derived class)”)”或或“子类子类( (son class)”)”。见图。见图11.2示意。示意。 图11.1 图11.2堂嘛窒惜僚虏丹瘟救值缕帽啮杭绅焊冷殆谆缸国央脓执膨阅匙量蛹涧刮临第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学一个派生类只从一个基类派生,这称为一个派生类只从一个基类派生,这称为单继承单继承(single inheritance)(single inheritance),这种继承关系所形成的层,这种继承关系所形成的层次是一个次是一个树形树形结构,见下图。结构,见下图。箭头表示继承的方向,从派生类指向基类。箭头表示继承的方向,从派生类指向基类。荡紊枕鲸概淄漆缮芝舞阵额浑层之借亩士灰诲娘垛洒纬术床锑使柄诞屋揣第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学一个派生类不仅可以从一个基类派生,也可以从一个派生类不仅可以从一个基类派生,也可以从多个基类派生。一个派生类有两个或多个基类的称多个基类派生。一个派生类有两个或多个基类的称为为多重继承多重继承(multiple inheritance)(multiple inheritance)。倍卓本等危躬烫该彬宝悲憋婆涣凯烛酞誓涨读吾棱林抛丸呆去濒樊陷彪陛第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学关于基类和派生类的关系:派生类是基类的具体化,而基类则是派生类的抽象。才扣叙鳞蹄悸土例雁容癌哼查冯妊见书嗓辐误轿孵袜娥挽锌放赛翠匹瘦安第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学声明派生类的一般形式为:声明派生类的一般形式为:class class 派生类名派生类名: : 继承方式继承方式 基类名基类名 派生类新增加的成员派生类新增加的成员 ; ;l继承方式包括继承方式包括: : publicpublic( (公用的公用的),),privateprivate( (私有的私有的) )和和protectedprotected( (受保护的受保护的) ),如果不写此项,则默认,如果不写此项,则默认为为privateprivate( (私有的私有的) )。11.2 11.2 派生类的声明方式派生类的声明方式苛他堂霄真加用耘壤岔听虾哆酝垮膏摸们妆得磅渴钵茬携量浅萌迫肖量诺第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学派生类分为两大部分派生类分为两大部分: : 一部分是从基类继承来的成员一部分是从基类继承来的成员另一部分是在声明派生类时增加的部分另一部分是在声明派生类时增加的部分每一部分均分别包括数据成员和成员函数。每一部分均分别包括数据成员和成员函数。11.3 11.3 派生类的构成派生类的构成跑蝉倚廊丰徐橇俯潜实惑郴抹阎揩葬颈允鞍蛹汀吊苦训镐梁示暂抨筷署报第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学编制编制派生派生类时类时可分可分四步四步 吸收基类的成员吸收基类的成员 改造基类成员改造基类成员 发展新成员发展新成员 重写构造函数与析构函数重写构造函数与析构函数 不论是数据成员,还是函数成员,除不论是数据成员,还是函数成员,除构造函数与析构函数外全盘接收构造函数与析构函数外全盘接收 声明一个和某基类成员同名的新成员,派声明一个和某基类成员同名的新成员,派生类中的新成员就屏蔽了基类同名成员称生类中的新成员就屏蔽了基类同名成员称为同名覆盖(为同名覆盖(override) 派生类新成员必须与基类成员不同名,它的派生类新成员必须与基类成员不同名,它的加入保证派生类在功能上有所发展。加入保证派生类在功能上有所发展。 构造一个派生类包括以下构造一个派生类包括以下4 4部分工作部分工作: :氏术了舒缠晌处荧线冈诸帜芝奄萤赋腹幌横咏矫胰笼敷癌天吸项藕掌颧饮第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学派生类对象结构派生类对象结构 对于下面的继承关系:对于下面的继承关系:class Father int a,b;public:/ 成员函数成员函数;class Son:public Father int c;public: / 成员函数成员函数;基类对象子类对象子类对象空间总是不小于基类对象cabab基类部分基类部分子类添加部分子类添加部分淌厚纹药硝肛钟正寅请咳粮绿铸挝斯聂烃屠篡冠膀未隐晋胚莽羌阿谰硫郊第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学11.4 11.4 派生类成员的访问属性派生类成员的访问属性继承可以公有继承,保护继承和私有继承。继承可以公有继承,保护继承和私有继承。公公有有继继承承是普通继承,基类可以为大多数应用服务。也可以重复继承。保保护护继继承承是“单传”继承,只继承给自己的后代,应用是以子孙的公有成员函数来对外展开服务的。私私有有继继承承是“绝版”继承,该基类只继承直接的子类,而不考虑让子类再继承下去。跟敞样貉邀畦孔酶三熟眨鲜既奏针访哄薯搓杜耍醒念尤暖淌赣讲遁吻赵铅第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学publicpublic继承:继承:l基类的基类的publicpublic成员成员, , 在派生类中成为在派生类中成为publicpublic成员成员l基类的基类的protectedprotected成员成员, , 在派生类中成为在派生类中成为protected protected 成员成员l基类的基类的privateprivate成员成员, , 在派生类中成为不可直接使用的成员在派生类中成为不可直接使用的成员11.4.1 11.4.1 公有继承公有继承 公有基类的成员公有基类的成员私有成员私有成员公有成员公有成员 保护成员保护成员在公有派生类中的访问属性在公有派生类中的访问属性不可访问不可访问公有公有保护保护表表11.1公用基类在派生类中的访问属性公用基类在派生类中的访问属性惩谈猪爹协荤外兰喝贞动砰狄夯难彪脱军屏呻捧利宪渊冯垂茶涅怔瓷篷粱第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学例:下面定义了两个具例:下面定义了两个具有单继承关系的类有单继承关系的类A和和B,其中,其中,A为基类,为基类,B为派生类:为派生类:class Aint x,y;public:void f();void g();class B : public Aint z;public:void h();尾眠者淀泻戴负瘴淖蛾崇舵刻赏扮廉凌涂蕉抿磅生寥遵碳幽倦郑辫惶稗惜第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学在在C+C+中对派生类有以下几点规定:中对派生类有以下几点规定:u派生类除了拥有基类的所有成员(基类的构造函数派生类除了拥有基类的所有成员(基类的构造函数和赋值操作符重载函数除外)外,也可以具有新的成和赋值操作符重载函数除外)外,也可以具有新的成员。员。class Aint x,y;public:void f();void g();class B : public Aint z;public:void h();void main()B b;b.f( ); /A类中的类中的 fb.g( ); /A类中的类中的gb.h( ); /B类中的类中的h邀檬馁痘辰尾创见苗五咬无箱恢证夷痴刺赵揩第户标燥戮趾缨歌凤伸甲渐第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学u派生类的定义用于描述派生类与基类的差别。派生派生类的定义用于描述派生类与基类的差别。派生类中可以给出新的成员,也可以对基类的成员进行重类中可以给出新的成员,也可以对基类的成员进行重定义。如果在派生类中对基类的某个成员进行重定义,定义。如果在派生类中对基类的某个成员进行重定义,则在派生类中对该成员的访问是针对派生类中重定义则在派生类中对该成员的访问是针对派生类中重定义的成员。的成员。class B : public Aint z;public:void f();void h() f( ); /B类中的类中的f g( ); /A类中的类中的g;void main( )B b;b.f( ); /B类中的类中的 fb.g ( ); /A类中的类中的gb.h( ); /B类中的类中的h屡持筹冰据歉香娶兴摧沧茫铰华幼险焊容死挖护臃命滋杠醉骡最鸳瑰器彪第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学u派生类成员名的作用域嵌套在基类的作用域中,对派生类成员名的作用域嵌套在基类的作用域中,对于基类的一个成员,如果派生类中没有定义与其同名于基类的一个成员,如果派生类中没有定义与其同名的成员,则该成员名在派生类的作用域内可见,否则,的成员,则该成员名在派生类的作用域内可见,否则,该成员名在派生类的作用域内不直接可见,如果要使该成员名在派生类的作用域内不直接可见,如果要使用,必须用基类名受限。例:用,必须用基类名受限。例:class B : public Aint z;public:void f( );void h( ) f( ); /B类中的类中的f A:f( ) /A类中的类中的f;void main( )B b;b.f( ); / B 类中的类中的 fb.A:f( ); /A类中的类中的f绚忠除酵绦荆朔琶侩雍蛆匙虹挖矗甭转渴咨糠恍碟晋愤篷介遍个掌毫逛踞第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学u即使派生类中定义了与基类同名但参数不同的成员即使派生类中定义了与基类同名但参数不同的成员函数,基类的同名函数在派生类中的作用域中也是不函数,基类的同名函数在派生类中的作用域中也是不直接可见的。例:直接可见的。例:class B : public Aint z;public:void f(int);void h( ) f(1); /Ok f( ); / A:f( ) / Ok;void main( )B b;b.f(1); / Okb.f( ); / b.A:f( ); / Ok漫弊雪诀擂吱袭菇僻彻屎降游馁伐自堤昧再猩萌灸犀措尔喜瑟安薯寺情吐第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学u定义派生类时一定要见到基类的定义,否则编译程定义派生类时一定要见到基类的定义,否则编译程序无法确定派生类对象需占多大内存空间以及派生类序无法确定派生类对象需占多大内存空间以及派生类中对基类成员的访问是否合法。例:中对基类成员的访问是否合法。例:class A;class B : public Aint z;public:void h( ) g( ); /Error没有没有g的原型的原型;B b; / Error无法确定无法确定 b 所需空间所需空间势湛婶窥馆细赠篱俱炼红栅辆霜蕴雁刷唐冯逗秋正借讳况罪窖瞅迈永富标第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学u如果在派生类中没有显式说明,基类的友元不是派如果在派生类中没有显式说明,基类的友元不是派生类的友元;如果基类是另一个类的友元,而该类没生类的友元;如果基类是另一个类的友元,而该类没有显式说明,则派生类也不是该类的友元。有显式说明,则派生类也不是该类的友元。u派生类不能直接访问基类的私有成员,必须要通过派生类不能直接访问基类的私有成员,必须要通过基类的非私有成员函数来访问基类的私有成员。例:基类的非私有成员函数来访问基类的私有成员。例:class A int x,y; public: void f( ); void g( )x;class B : public Aint z;public:void h( )x /Error, x为基类的私有成员为基类的私有成员g( ); /Ok, 通过函数通过函数g访问基类的私有成员访问基类的私有成员x;效启耿侵瓢扇寅锑丙獭蔓颈责占皂布携犯概媚饺及亦靶烦桓牵硷膛峙不舒第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学在派生类中对基类成员的访问在派生类中对基类成员的访问u一个类有两种用户:实例用户和派生类。例:一个类有两种用户:实例用户和派生类。例:u一个类存在两个对外接口一个类存在两个对外接口l给实例用户使用:由类的给实例用户使用:由类的publicpublic成员构成成员构成l提供给派生类使用:由类的提供给派生类使用:由类的publicpublic和和protectedprotected成员构成成员构成class A ;class B : public A /派生类派生类; void f( )/实例用户实例用户 A a;class A protected:int x,y; public:void f( );class B : public A /派生类派生类 void h() x / Ok y / Ok f( ); / Ok; void f( )/实例用实例用户户 A a;a.x / Errora.y / Errora.f( ); / Ok;绰蠕翁棉吕胜沙挤咽淬捻剃蚜彭廓鸡巫惭布弯梯胃净感虫跑耳讣娠尤赞鼓第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学u类的聚集:一个类只有一个接口,即类的实例用户类的聚集:一个类只有一个接口,即类的实例用户接口。例:以继承和聚集实现的代码重用。接口。例:以继承和聚集实现的代码重用。class A public :void f();void g();class B : public A public :void h(); class B A a;public :void f()a.f();void g()a.g();void h();壁沪惦墩唐最蓖猎丹袜培禹鹃臃澜效榔告爱净掐澡至拱坷或哉崖烫嗣曾登第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学u继承实现子类型,派生类可以看成基类的子类型。继承实现子类型,派生类可以看成基类的子类型。u子类型的作用:发给基类对象的消息也能发给派生子类型的作用:发给基类对象的消息也能发给派生类对象,以及基类的对象标识可以标识派生类对象。类对象,以及基类的对象标识可以标识派生类对象。class A public :void f();class B : public A public :void g(); 以下操作合法:以下操作合法:A a,*p;B b,*q;b.f();a=b;p=&b;以下操作非法:以下操作非法:b=a; /Error b有不确定的成员数有不确定的成员数据据q=&a; /Error用用b去改变去改变a的状态,属于的状态,属于b但不属于但不属于a的成员将被忽略的成员将被忽略A类指针类指针p指向指向B类对象类对象b趋罗衡毗颂凑维尧陪学冰雕乞霸漫拒研筏迂糟匣匪梁秦冗汛敞哭钨撑塔培第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学例例11.1 11.1 访问公有基类的成员。访问公有基类的成员。Class Student/声明基类声明基类public: /基类公用成员基类公用成员 void get_value( ) cinnumnamesex; void display( ) cout num: numendl; cout name: nameendl; cout sex: sexendl; private : /基类私有成员基类私有成员 int num; char name8; char sex; class Student1: public Student /以以public方式声明派生类方式声明派生类Student1犀燎凌橙荒录筒语很竭受哎汗佣烯肾枝倒谷纤散缀衍悦诱牛妹拉磁侗荫纱第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学 public:void display_1( )cout num: numendl; cout name: nameendl; /引用基类的私有成员,错误引用基类的私有成员,错误 cout sex: sexendl; cout age: ageendl; /引用派生类的私有成员,正确引用派生类的私有成员,正确 cout address: addrendl; /引用派生类私有成员,正引用派生类私有成员,正确确private: int age; char addr12; ;结论:结论:由于基类的私有成员对派生类来说是不可访问的,由于基类的私有成员对派生类来说是不可访问的,因此在派生类中的因此在派生类中的display_1display_1函数中直接引用基类函数中直接引用基类的私有数据成员的私有数据成员numnum,namename和和sexsex是不允许的。是不允许的。只能通过基类的公用成员函数来引用基类的私有只能通过基类的公用成员函数来引用基类的私有数据成员。数据成员。驼坚曹丘阳陛叔杠疽蕉瀑蕾绳娥黑顷娟呕嫉脊轴焚介媚芬辛娜僧朵抱络欠第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学可以将派生类可以将派生类Student1的声明改为:的声明改为:class Student1: public Student /以以public方式声明派生类方式声明派生类Student1public:void display_1( ) cout age: ageendl; /派生类的私有成员,正确派生类的私有成员,正确cout address: addrageaddr;private:int age; string addr;挤后拂籍辅后漓候年舒蟹胡登底陡系代华馁饭粪凳堕土卤漆仇璃志完湘蛀第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学可以这样写可以这样写main函数函数: int main( )Student1 stud; stud. get_value ( );stud. get_value_1 ( );stud.display( ); stud.display_1(); return 0; void display_1( ) display( ) ;cout“ age: “ageendl; cout“ address: “addrageaddr;互翁陌决瞧努筹厦岁逮霜倒亩挡胰绿瘫但肮呀休翅冀之哪场赛翰孕栈北北第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学privateprivate继承:继承:l基类的基类的publicpublic成员成员, , 在派生类中成为在派生类中成为privateprivate 成员成员l基类的基类的protectedprotected成员成员, , 在派生类中成为在派生类中成为privateprivate成员成员l基类的基类的privateprivate成员成员, , 在派生类中成为不可直接使用的成员在派生类中成为不可直接使用的成员11.4.2 11.4.2 私有继承私有继承 私有基类的成员私有基类的成员私有成员私有成员公有成员公有成员 保护成员保护成员在私有派生类中的访问属性在私有派生类中的访问属性不可访问不可访问私有私有私有私有表表11.1私有基类在派生类中的访问属性私有基类在派生类中的访问属性次岸缴网席汗椭中炔充块忘扒壁傅灌卢揖柔丸渤闽母访棕新箱永亭给拉讨第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学图11.7表示了各成员在派生类中的访问属性。炸厉酸救枕伐八执糊饰纪焰喳废颊狠泅蔚鹰嘛搬察隙吠沛哎闹姨贯板抿茨第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学例例11.2 11.2 将例将例11.111.1中的公用继承方式改为用私有继承方中的公用继承方式改为用私有继承方式式( (基类基类StudentStudent不改不改) )。可以写出私有派生类如下可以写出私有派生类如下: :class Student1: private Student/用私有继承方式声明用私有继承方式声明public:void display_1( ) cout“age: “ageendl; cout“address: “addrendl; private:int age; char addr12;int main( )Student1 stud1; stud1.display(); /错误错误stud1.display_1( ); /正正确确stud1.age=18; /错误错误return 0; 朴联绥即娘密坤锗箱种诺丹布执辨疆青汗熄坞理培扯贝土贞砸牙廊鼻潍冯第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学结论结论: : (1) (1) 不能通过派生类不能通过派生类对象对象( (如如stud1) )引用从引用从私有基类私有基类继承过来的任何成员继承过来的任何成员。(2) (2) 派生类的成员函数不能访问派生类的成员函数不能访问私有基类私有基类的私有成的私有成员,但可以访问私有基类的公用成员。员,但可以访问私有基类的公用成员。 在派生类外不能通过派生类对象调用私有基类在派生类外不能通过派生类对象调用私有基类的公用成员函数,但可以通过派生类的成员函数调的公用成员函数,但可以通过派生类的成员函数调用私有基类的公用成员函数用私有基类的公用成员函数( (此时它是派生类中的此时它是派生类中的私有成员函数,可以被派生类的任何成员函数调用私有成员函数,可以被派生类的任何成员函数调用) )。睦叉相逾毡跺怂疹硅锣显攻仰衣泵敖涉剁毒璃赂彦揩竖碌丁市柞储泽延首第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学可将上面的私有派生类的成员函数定义改写为可将上面的私有派生类的成员函数定义改写为void display_1( )display(); /调用基类的公用成员函数调用基类的公用成员函数 coutage: ageendl; /派生类的私有数据成员派生类的私有数据成员coutaddress: addrendl; /派生类的私有数据成员派生类的私有数据成员main函数可改写为函数可改写为int main( )Student1 stud1; stud1.display_1( ); /Student1类的公用函数类的公用函数 return 0;娥躇怀束脚赣绦输乎宇浮虱偷莎涝棍歉怯颁撕品使凰官奖萨娠慨符乏菩年第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学由于私有派生类限制太多,使用不方便,一般不常使用。毒胀原擞岗蝴脚鸭驻卸战鸿疑涧嫩胎挑袋蔫说猫踏迫徐歹惭嘶荫辈认宪柏第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学11.4.3 11.4.3 保护成员和保护继承保护成员和保护继承protected protected 继承:继承:l基类的基类的publicpublic成员成员, , 在派生类中成为在派生类中成为protected protected 成员成员l基类的基类的protectedprotected成员成员, , 在派生类中成为在派生类中成为protected protected 成员成员l基类的基类的privateprivate成员成员, , 在派生类中成为不可直接使用的成员在派生类中成为不可直接使用的成员基类中的成员基类中的成员 在公有派生类在公有派生类在私有派生类在私有派生类在保护派生类在保护派生类私有成员私有成员不可访问不可访问不可访问不可访问不可访问不可访问公有成员公有成员公有公有私有私有保护保护保护成员保护成员保护保护私有私有保护保护表表11.3基类成员在派生类中的访问属性基类成员在派生类中的访问属性宰羡踢峪辆蚀伙络皋少眶隅挂谱马诀明左伦示汪酝侧馋仆嚏毛叮衰坎辰萝第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学保护成员可以被派生类的成员函数引用。但不能被保护成员可以被派生类的成员函数引用。但不能被实例函数引用。实例函数引用。拥故惑隙矩婉嵌甘扔众拼臼备站挡榴铂道访欧达丢毗喉庄庸饲贬译溃胀潮第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学例:例:class B1 int a; void f( )couta; public: int b; void g( )couta; protected: int c; void k( )couta; ;对派生类:对派生类:class B2: public B1public: void df( ) couta; / coutb; coutc; f( ); / g( ); k( ); ;对实例函数对实例函数void main( ) B1 b1; coutb1.a;/ coutb1.b; coutb1.c; / b1.f( ); / b1.g( ); b1.k( ); / 宙堂延卉捉倚秩酥螺褒蹿聊忘谷吠甘阑木粥长法伪恨补卷趟晃帕剂闰或裂第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学(1) (1) 在派生类中,成员有在派生类中,成员有4 4种不同的访问属性种不同的访问属性: : 派生类中的成员派生类中的成员在派生类中在派生类中 在派生类外在派生类外在下层公用派生类中在下层公用派生类中公用的成员公用的成员可以可以可以可以可以可以受保护的成员受保护的成员可以可以不可以不可以可以可以私有的成员私有的成员可以可以不可以不可以不可以不可以不可访问的成员不可访问的成员不可以不可以不可以不可以不可以不可以表表11.411.4派生类中的成员的访问属性派生类中的成员的访问属性遏纤瞅焊颁缅备预撰烬及忿乘屡中惠威蛰疙太攒蝴跃哨幽鳖氮摇坍拒矿恍第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学例例11.3 在派生类中引用保护成员。在派生类中引用保护成员。#include #include using namespace std;class Studentpublic: void display( ); protected :int num;string name;char sex;void Student:display( ) coutnum: numendl; coutname: nameendl; coutsex: sexendl; class Student1: protected Studentpublic:void display1( ); private:int age; char addr 12; ;礼芝己驯康尺缘完旭秘绿霓带咋俩蹋界纽劫慧膨瘤俺诚孔延库丙娇耘介徒第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学void Student1:display1( ) /定义派生类公用成员函数定义派生类公用成员函数 coutnum: numendl; /基类的保护成员,合法基类的保护成员,合法 coutname: nameendl; coutsex: sexendl; coutage: ageendl; /派生类的私有成员,合法派生类的私有成员,合法 coutaddress: addrendl; int main( ) Student1 stud1; stud1.display1( ); stud1.num=10023; / 错误,外界不能访问保护成员错误,外界不能访问保护成员return 0; 摩及酸链企辟辟慎咽黍翰奢套挞缩婚惮利喻秀帝窒噬早塔捧瘩本类陋浊胚第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学在派生类的成员函数中引用基类的保护成员是合法的。保护成员和私有成员不同之处,在于把保护成员的访问范围扩展到派生类中。注意: 在程序中通过派生类Student1的对象stud1的公用成员函数display1去访问基类的保护成员num.name和sex,不要误认为可以通过派生类对象名去访问基类的保护成员。私有继承和保护继承方式很容易搞错,一般不常用。呛脉愤摈生洼腐坠墅监九屎畅拼裸外辰耘帧疲舟寒灯锤吮立瘩嫉浅雪达瞒第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学 11.4.4 11.4.4 多级派生时的访问属性多级派生时的访问属性图11.9如果有图11.9所示的派生关系: 类A为基类,类B是类A的派生类,类C是类B的派生类,则类C也是类A的派生类。类B称为类A的直接派生类,类C称为类A的间接派生类。类A是类B的直接基类,是类C的间接基类。在多级派生的情况下,各成员的访问属性仍按以上原则确定。工碰嘿嫁阑体匆滇准偶恒欠邹祥吠宅堵冤页皑译蕊底揣碑措及恃戮灾杏馒第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学例例11.4 多级派生访问属性。多级派生访问属性。class Apublic: int i; protected: void f2( ); int j; private: int k;class B: public A public:void f3( ); protected:void f4( ); private: int m;class C: protected Bpublic:void f5( ); private: int n;class B:public: void f3( ); int i;protected: void f4( ); void f2( ); int j;private: int m;class C:public: void f5( );protected: void f4( ); void f2( ); int j; void f3( ); int i;private: int n;举畦圈央妓撂存辞清庭经小似捎皇嚎洁掠傲慢季民统冷感专腥贫现驳良尿第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学u在派生类中是不能访问基类的私有成员的,私有成员只能被本类的成员函数所访问,毕竟派生类与基类不是同一个类。u在多级派生时:l采用公用继承方式,那么直到最后一级派生类都能访问采用公用继承方式,那么直到最后一级派生类都能访问基类的公用成员和保护成员。基类的公用成员和保护成员。l采用私有继承方式,经过若干次派生之后,基类的所有采用私有继承方式,经过若干次派生之后,基类的所有的成员已经变成不可访问的了。的成员已经变成不可访问的了。l采用保护继承方式,在派生类外是无法访问派生类中的采用保护继承方式,在派生类外是无法访问派生类中的任何成员的。经过多次派生后,很难记住哪些成员可以访任何成员的。经过多次派生后,很难记住哪些成员可以访问,哪些成员不能访问。问,哪些成员不能访问。常用的是公用继承常用的是公用继承!帆等褐婪虹挺甥恍昨疥卤啮捶退环啤汹售猖淋虫笑诵穷徽寡咒愧嵌迹漾证第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学11.5 11.5 派生类的构造函数和析构函数派生类的构造函数和析构函数用户在声明类时可以不定义构造函数,系统会自用户在声明类时可以不定义构造函数,系统会自动设置一个默认的构造函数。动设置一个默认的构造函数。在设计派生类的构造函数时,希望在执行派生类在设计派生类的构造函数时,希望在执行派生类的构造函数时,使派生类的数据成员和基类的数据的构造函数时,使派生类的数据成员和基类的数据成员同时都被初始化。成员同时都被初始化。解决这个问题的思路是解决这个问题的思路是: 在执行派生类的构造函在执行派生类的构造函数时,调用基类的构造函数。数时,调用基类的构造函数。峰梗晦笼裸算咎港树跺挨豹篙鳖饲挟详寅赫跑锤惫便虱搬决隙卑睡艳哨沪第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学例例11.5 简单的派生类的构造函数。简单的派生类的构造函数。#include #includeusing namespace std;class Student/声明基类声明基类Student public: Student(int n,string nam,char s) /基类构造函数基类构造函数 num=n; name=nam; sex=s; Student( ) /基类析构函数基类析构函数protected: /保护部分保护部分 int num; string name; char sex ; ;11.5.1 11.5.1 简单的派生类的构造函数简单的派生类的构造函数佑宰裙京恳辱诅蚕遵孝滨局外邯腕靶铸疚熄溺蓟暮群遏晨叔匣剥仿痒赘拘第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学class Student1: public Student public: Student1(int n,string nam, char s, int a,string ad): Student(n,nam,s) age=a; addr=ad; void show( ) coutnum: numendl; coutname: nameendl; coutsex: sexendl; coutage: ageendl; coutaddress: addrendl; Student1( ) private:调用基类构造函数调用基类构造函数派生类新增的数据派生类新增的数据成员初始化成员初始化墨小磷条卡髓卡滞呐扒富锑致簧黑桅寓托掳滦乳戒枪全缆抠国环拉抱换砷第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学 int age; string addr; ;int main( ) Student1 stud1(10010,Wang-li,f,19,115 Beijing Road,Shanghai); Student1 stud2(10011,Zhang-fun,m,21,213 Shanghai Road,Beijing); stud1.show( ); stud2.show( ); return 0;运行结果为运行结果为num: 10010name: Wang-lisex: fage: 19address: 115 Beijing Road,Shanghainum: 10011name: Zhang-funsex: mage: 21address: 213 Shanghai Road,Beijing驾衙剿奥昭纤正炽筒宾府宣绦戳的缚醋岿拦销茎虽娥既笨僵烘票畜深睫乖第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学派生类构造函数的一般形式为派生类构造函数的一般形式为:派生类构造函数名派生类构造函数名(总参数表列总参数表列):基类构造函数名基类构造函数名(参数表列参数表列) 派生类中新增数据成员初始化语句派生类中新增数据成员初始化语句例如:例如:继悸钱晃括瓢陋畜羔茧爆才岸从鳃肉鞋棱您阳瘪瞬菲啼查冗缴谋盔矫拌姨第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学派生类构造函数在类外定义,而在类体中函数的声明派生类构造函数在类外定义,而在类体中函数的声明: : Student1(int n,string nam,char s,int a,string ad);在类的外面定义派生类构造函数在类的外面定义派生类构造函数: : Student1 Student1(int n,string nam,char s,int a,string ad):Student(n,nam,s) age=a; addr=ad;埋玖双靖胰尾留港那埋靳九确回忍液状炭甭柄烂续示脱湾眼弧狄柠退需势第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学注意注意: : u在类中对派生类构造函数在类中对派生类构造函数声明声明时,不包括基类构时,不包括基类构造函数名及其参数表列(即造函数名及其参数表列(即Student(nStudent(n,namnam,s)s))。)。u调用基类构造函数时的实参是从派生类构造函数调用基类构造函数时的实参是从派生类构造函数总参数表中得到的,也可以不从派生类构造函数总总参数表中得到的,也可以不从派生类构造函数总参数表中传递过来,而直接使用常量或全局变量。参数表中传递过来,而直接使用常量或全局变量。例例: : Student1(string nam,char s,int a,string ad):Student(10010,nam,s) age=a; addr=ad;常量常量葡范扼前恳聋等探年殷雀坐巢楔芍缔糖勘葱金掂硅票卡谷证娱谓么谍残澎第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学u利用初始化表对构造函数的数据成员初始化利用初始化表对构造函数的数据成员初始化 Student1(int n, string nam,char s,int a, string ad): Student(n,nam,s),age(a),addr(ad)u在建立一个派生类对象时,执行构造函数的顺序是在建立一个派生类对象时,执行构造函数的顺序是: : l派生类构造函数先调用基类构造函数;派生类构造函数先调用基类构造函数;l再执行派生类构造函数本身再执行派生类构造函数本身( (即派生类构造函数的函数体即派生类构造函数的函数体) )。u在派生类对象释放时,执行析构函数的顺序是在派生类对象释放时,执行析构函数的顺序是: : l先执行派生类析构函数;先执行派生类析构函数;l再执行其基类析构函数。再执行其基类析构函数。筷瑰痹服立旺岸丽湘汛醛矽骚树韭陷瞪倦者贬果润鳖己隙肪士肪凹滁庸权第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学类的数据成员中还可以包含类对象。类的数据成员中还可以包含类对象。例例: : Student s1; Student s1; / s1/ s1是是StudentStudent类的对象类的对象s1s1就是类对象中的就是类对象中的内嵌对象内嵌对象,称为,称为子对象子对象(subobject)(subobject),即对象中的对象。,即对象中的对象。11.5.2 11.5.2 有子对象的派生类的构造函数有子对象的派生类的构造函数辅兄臆赚水洲皿皂吻诞锻阻攻诬僻悬揭墅板刊恭纫居旬炕竿低早础碱伊欺第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学例例11.6 包含子对象的派生类的构造函数。包含子对象的派生类的构造函数。#include #include using namespace std;class Student public: Student(int n, string nam ) num=n; name=nam; void display( ) coutnum:numendlname:nameendl;protected: int num; string name;class Student1: public Student浸见郭肖包萤宜龄观辜依羊撒摇乐货宁访蛤运掳掳穷虞期欠春牺妒究踌墒第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学 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( ) coutThis student is:endl; display(); coutage: ageendl; coutaddress: addrendl; void show_monitor( ) coutendlClass monitor is:endl; monitor.display( ); /调用基类成员函调用基类成员函数数 基类参数基类参数子类参数子类参数派生类参数派生类参数1、基类构造函数、基类构造函数2、子类构造函数、子类构造函数3、派生类构造函数、派生类构造函数塔邱憨寐屉锈余魂按领爪蟹钩戈呢具牛秘攻客炊木璃次蹲俭绢纶妨颧愉椰第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学private: Student monitor; /定义子对象定义子对象(班长班长) int age; string addr; ;int main( )Student1 stud1(10010,Wang-li,10001,Li-sun,19,115 Beijing Road,Shanghai); stud1.show( ); stud1.show_monitor(); /输出子对象的数据输出子对象的数据return 0;运行时的输出如下运行时的输出如下: This student is:num: 10010name: Wang-liage: 19address:115 Beijing Road,Shanghai Class monitor is:num:10001name:Li-sun蜡恶封披腰绥盼媳充洒幌间企眶谰瞧壳蛹怨惶甭迸典斥扑庄厨养沂痪晦叛第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学定义派生类构造函数的一般形式为:定义派生类构造函数的一般形式为:派生类构造函数名(总参数表列)派生类构造函数名(总参数表列): : 基类构造函数名(参数表基类构造函数名(参数表列),子对象名列),子对象名( (参数表列参数表列) ) 派生类中新增数据成员初始化语句派生类中新增数据成员初始化语句 u总参数表列中的参数,应当包括基类构造函数、子对象的参总参数表列中的参数,应当包括基类构造函数、子对象的参数表列中的参数和派生类中新增数据成员的参数。数表列中的参数和派生类中新增数据成员的参数。u基类构造函数和子对象的次序可以是任意的。基类构造函数和子对象的次序可以是任意的。u派生类构造函数的任务派生类构造函数的任务: : 对基类、子对象和派生类数据成员对基类、子对象和派生类数据成员做初始化。做初始化。考经窍侯怜喻脉起镶近缴妓汽撂铸杜幸榜晋揣钒往摈蛮沂馁贾符昨栖膘宜第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学执行派生类构造函数的顺序是执行派生类构造函数的顺序是: : l调用基类构造函数,对基类数据成员初始化;调用基类构造函数,对基类数据成员初始化;l调用子对象构造函数,对子对象数据成员初始化;调用子对象构造函数,对子对象数据成员初始化;l再执行派生类构造函数本身,对派生类数据成员再执行派生类构造函数本身,对派生类数据成员初始化。初始化。滋戴凿蔑枪席嗣枯眯且轮哺渐疑客芭蓟照性碑蔗唉希痕镊翟缚浊礼邱咬卢第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学一个类不仅可以派生出一个派生类,派生类还可以继一个类不仅可以派生出一个派生类,派生类还可以继续派生,形成派生的层次结构。续派生,形成派生的层次结构。11.5.3 11.5.3 多层派生时的构造函数多层派生时的构造函数例例11.7 多级派生情况下派生类的构造函数。多级派生情况下派生类的构造函数。#include #includeusing namespace std;class Student public: Student(int n, string nam ) num=n; name=nam; void display( ) coutnum:numendl; coutname:nameendl; protected: int num; string name; ; 蛊亚里样率顷啤戮细酝酵俘谎碟植惑刽信否丰吵宠未仪亢操饵祥格傣腆只第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学 class Student1: public Student public: Student1(int n,string nam,int a):Student(n,nam) age=a; void show( ) display( ); coutage: ageendl; private: int age; ;class Student2:public Student1 /声明间接公用派生类声明间接公用派生类 public:垛胚法带驳凯咳龚射漆粹谈搐独图壮闺去蚀缚董霹寝侩趣糊蓟短谆瓢噪歌第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学 /下面是间接派生类构造函数下面是间接派生类构造函数 Student2(int n, string nam,int a,int s): Student1(n,nam,a) score=s; void show_all( ) show( ); /输出输出num、name和和age coutscore:scoreendl; private: int score; ;int main( ) Student2 stud(10010,Li,17, 89); stud.show_all( ); return 0; 运行时的输出如下: num:10010name:Liage:17score:89 贡在胁朗姆劈甸仕誓题炳赠犬裁丧缆贞巳烷浊阮莽统嫉色囊承透蝴总单刑第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学其派生关系如下图。胁泵卜唆亢炒娘溉扬鸵捧荷笔店暇贾阿拐耳杜累挫烙褪巫鸭蓟曾在架出川第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学基类和两个派生类的构造函数的写法基类和两个派生类的构造函数的写法: : u基类的构造函数首部基类的构造函数首部: : Student(int n, string nam)u派生类派生类Student1的构造函数首部的构造函数首部: Student1(int n, string nam,int a):Student(n,nam) u派生类派生类Student2的构造函数首部的构造函数首部: Student2(int n, string nam,int a,int s):Student1(n,nam,a)1.初始化的顺序是初始化的顺序是: 1.1.先初始化基类的数据成员先初始化基类的数据成员numnum和和namename。2.2.再初始化再初始化Student1Student1的数据成员的数据成员ageage。3.3.最后再初始化最后再初始化Student2Student2的数据成员的数据成员scorescore。中废禽呼肆傣翁靶蹄贝芒虹淳稍纫夹膜仰痉熏践塞丁妒软阅吁曲故亢奏喊第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学使用派生类构造函数时,有以下特殊形式使用派生类构造函数时,有以下特殊形式: : u当不需要对派生类新增的成员进行任何初始化操作当不需要对派生类新增的成员进行任何初始化操作时,派生类构造函数的函数体可以为空,即构造函数时,派生类构造函数的函数体可以为空,即构造函数是空函数,如是空函数,如: :Student1(int n, string nam,int n1, string nam1):Student(n,nam), monitor (n1,nam1) u如果基类中没有定义构造函数,或定义了没有参数如果基类中没有定义构造函数,或定义了没有参数的构造函数,那么在定义派生类构造函数时可不写基的构造函数,那么在定义派生类构造函数时可不写基类构造函数。调用派生类构造函数时系统会自动首先类构造函数。调用派生类构造函数时系统会自动首先调用基类的默认构造函数。调用基类的默认构造函数。11.5.4 11.5.4 派生类构造函数的特殊形式派生类构造函数的特殊形式辟挎瑟锻姻釉澜篇洞枕洒熔留述阎蒂仕宰热行仕凝哎霹医措嗡片族绘练杉第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学u如果基类和子对象类型都没有定义带参数如果基类和子对象类型都没有定义带参数的构造函数,而且也不需对派生类自己的数的构造函数,而且也不需对派生类自己的数据成员初始化,则可以不必显式地定义派生据成员初始化,则可以不必显式地定义派生类构造函数。在建立派生类对象时,系统会类构造函数。在建立派生类对象时,系统会自动调用派生类的默认构造函数,并在执行自动调用派生类的默认构造函数,并在执行派生类默认构造函数的过程中,调用基类的派生类默认构造函数的过程中,调用基类的默认构造函数和子对象类型默认构造函数。默认构造函数和子对象类型默认构造函数。霞欲傀苗渴动垒绕藉灿吕训与丘胆城械稿敦乞新揽黄汤鄂棱珐咽罗藏垒染第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学u如果在基类中既定义无参的构造函数,又如果在基类中既定义无参的构造函数,又定义了有参的构造函数定义了有参的构造函数( (构造函数重载构造函数重载) ),则,则在定义派生类构造函数时,既可以包含基类在定义派生类构造函数时,既可以包含基类构造函数及其参数,也可以不包含基类构造构造函数及其参数,也可以不包含基类构造函数。在调用派生类构造函数时,根据构造函数。在调用派生类构造函数时,根据构造函数的内容决定调用基类的有参的构造函数函数的内容决定调用基类的有参的构造函数还是无参的构造函数。还是无参的构造函数。剧讲留规恫酞招障彻硕誓稿胯貉狞卤桐钟灿踊蔬拧句铭妥漠峙升炮相茹赋第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学u对派生类中所增加的成员进行清理工作对派生类中所增加的成员进行清理工作, , 需要定义需要定义自己的析构函数。自己的析构函数。u基类的清理工作仍然由基类的析构函数负责。基类的清理工作仍然由基类的析构函数负责。u在执行派生类的析构函数时,系统会自动调用基类在执行派生类的析构函数时,系统会自动调用基类的析构函数和子对象的析构函数,对基类和子对象进的析构函数和子对象的析构函数,对基类和子对象进行清理。行清理。u 调用的顺序与构造函数正好相反调用的顺序与构造函数正好相反: : l先执行派生类自己的析构函数先执行派生类自己的析构函数; ;l然后调用子对象的析构函数然后调用子对象的析构函数; ;l最后调用基类的析构函数。最后调用基类的析构函数。11.5.5 11.5.5 派生类的析构函数派生类的析构函数淘攫排猎酒啤掖距壕嚣驴噶笼笆偷竖晾豁巨览迭现演道韩澜院推剑涝魁挟第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学多重继承:多重继承:派生类同时继承多个基类。派生类同时继承多个基类。11.6 多重继承多重继承11.6.1 声明多重继承的方法声明多重继承的方法如果已声明了类A、类B和类C,可以声明多重继承的派生类D:class D: public A, private B, protected C类类D新增加的成员新增加的成员挖蒲杂稼铀形泡撵燕奋新卑囚每跪织盾训弛冷想劳赂意馁蹄斜侥破眨猖荆第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学D D是多重继承的派生类,它以公用继承方式继承是多重继承的派生类,它以公用继承方式继承A A类,类,以私有继承方式继承以私有继承方式继承B B类,以保护继承方式继承类,以保护继承方式继承C C类。类。D D按不同的继承方式的规则继承按不同的继承方式的规则继承A,B,CA,B,C的属性,确定的属性,确定各基类的成员在派生类中的访问权限。各基类的成员在派生类中的访问权限。幂荐屑头和癣罩死标休陡峻妓梳伺孰僚钻争哟油吕骄痢特缀跺腋豢嚷丧乞第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学多重继承派生类的构造函数形式。如:11.6.2 11.6.2 多重继承派生类的构造函数多重继承派生类的构造函数派生类构造函数名派生类构造函数名(总参数表列总参数表列): 基类基类1构造函数构造函数(参数表列参数表列), 基类基类2构造函数构造函数(参数表列参数表列), 基类基类3构构造函数造函数 (参数表列参数表列) 派生类中新增数成员据成员初始化语句派生类中新增数成员据成员初始化语句u各基类的排列顺序任意。各基类的排列顺序任意。u派生类构造函数的执行顺序同样为派生类构造函数的执行顺序同样为: : 先调用基类的构造先调用基类的构造函数,再执行派生类构造函数的函数体。函数,再执行派生类构造函数的函数体。u调用基类构造函数的顺序是调用基类构造函数的顺序是按照声明派生类时基类出现按照声明派生类时基类出现的顺序。的顺序。肖钦球廓于吴息漱拜蜘烂肉佩刨接骑载募万鲤肤恐职潞授健蔡率吏彬届温第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学例例11.8 11.8 声明一个教师声明一个教师(Teacher)(Teacher)类和一个学生类和一个学生(Student)(Student)类,用多重继承的方式声明一个研究生类,用多重继承的方式声明一个研究生(Graduate)(Graduate)派生类。教师类中包括数据成员派生类。教师类中包括数据成员namename( (姓名姓名) )、age(age(年龄年龄) )、title(title(职称职称) )。学生类中包括。学生类中包括数据成员数据成员name1(name1(姓名姓名) )、age(age(性别性别) )、score(score(成绩成绩) )。在定义派生类对象时给出初始化的数据,然后输出在定义派生类对象时给出初始化的数据,然后输出这些数据。这些数据。#include #include using namespace std;class Teacher public: Teacher(string nam,int a, string t) name=nam; age=a; title=t; void display( ) coutname:nameendl; coutageageendl; couttitle:titleendl; protected: string name; int age; string title; /职称职称;兵纬拿函弓砸枝吐汗斟钢翁胆羽言呐单模抗谓颈矽气侣哆千遥锻毒采萌监第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学class Student public: Student(char nam,char s,float sco) strcpy(name1,nam); sex=s; score=sco; void display1( ) coutname:name1endl; coutsex:sexendl; coutscore:scoreendl; protected: char name18; char sex; float score; /成绩成绩 ;妊盔陪帧幂竣项源妊吮炙莫鹰舀妨续药饯庞阉特堑森肆礼悬彤贪谆蔽阳挟第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学class Graduate:public Teacher,public Student public: Graduate(char nam,int a,char s, string t,float sco,float w): Teacher(nam,a,t),Student(nam,s,sco),wage(w) void show( ) /输出研究生的有关数输出研究生的有关数据据 coutname:nameendl; coutage:ageendl; coutsex:sexendl; coutscore:scoreendl; couttitle:titleendl; coutwages:wageendl; private: float wage; /工资工资 ;如果如果Teacher和和Student类中类中都是都是name,会出现二义性。会出现二义性。正确作法可加限定:正确作法可加限定:Teacher:name阉垛抿帅朔侣医妈拘柿娘峰景狈昧软仙砍坐以风幌拭会鸦蠢柑绳谷娇惺屏第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学 int main( ) Graduate grad1(“Wang-li”,24,f, “assistant”,89.5,1234.5); grad1.show( ); return 0;在两个基类中分别用在两个基类中分别用namename和和name1name1来代表姓名,其实这来代表姓名,其实这是同一个人的名字,从是同一个人的名字,从GraduateGraduate类的构造函数中可以看类的构造函数中可以看到总参数表中的参数到总参数表中的参数namnam分别传递给两个基类的构造函分别传递给两个基类的构造函数,作为基类构造函数的实参。数,作为基类构造函数的实参。程序运行结果如下程序运行结果如下: name: Wang-li age: 24sex:fscore: 89.5 title: assistancewages: 1234.5 赊粕怨闻虱惰赔病衣看负瓤衅终梢替幅尧向献腻栓获猎究绿泵绰备裳嫉同第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学在多重继承中,当多个基类中包含同名成员时,它们在派生类中就会出现名冲突问题。例:11.6.3 11.6.3 多重继承引起的二义性问题多重继承引起的二义性问题class Apublic: int a; void display( );class Bpublic: int a; void display( );class C :public A,public Bpublic : int b; void show();void main()C c1;c1.a=3;c1. display( );同名冲突同名冲突郎勤靴浮琼讼且柄智缚补隧醒籽构唤子蜀伙叹此佣售窝膏契扒悲丸暇策尉第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学(1) 两个基类有同名成员。如图所示。牌模冶尸唆岗咎冻吞秸棠蛔难囱逼故酥撕存胜吧腑飞虾蓉期酱券带睦卑臣第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学class Apublic: int a;void display( );class Bpublic: int a; void display( );class C :public A,public Bpublic : int b; void show();void main() C c1; c1.a=3; /二义性二义性 c1.display(); /二义性二义性void main() C c1; c1.A:a=3; /正确正确 c1. A: display(); /正确正确void show() A:a=3; /不必加对象名不必加对象名 A:display(); /不必加对象名不必加对象名砷侦误场屑苹动咯宛铀休次钟恫咕嘴决蒙狞逆闹啸士柞迫浅痕漫适讯挑挝第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学两个基类有同名成员的表示:两个基类有同名成员的表示:汇愿竖情桨展薛演糯身屉清列桅岛败暇往梨毁杨要说囤炔搜国涡挡携芬骚第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学(2) (2) 两个基类和派生类三者都有两个基类和派生类三者都有同名成员。同名成员。将上面的将上面的C C类声明改为类声明改为class C :public A,public Bint a; void display();void main()C c1;c1.a=3; /访问访问C C中的成员中的成员c1.display( ); /访问访问C C中的成员中的成员void main()C c1;c1.A:a=3; /访问访问A A中的成员中的成员c1. A: display( ); /访问访问A A中的成员中的成员基类中的同名基类中的同名成员被覆盖成员被覆盖到乱剪鬼预遵胀倍警龙切匡聘械援谰戈峙蛙诲烛却醉妻地肖赤萝攒支尝娱第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学规则规则: : 基类的同名成员在派生类中被屏蔽,成为基类的同名成员在派生类中被屏蔽,成为“不不可见可见”的,或者说,派生类新增加的同名成员的,或者说,派生类新增加的同名成员覆盖了基类中的同名成员。覆盖了基类中的同名成员。注意注意: : v不同的成员函数,只有在函数名和参数个数不同的成员函数,只有在函数名和参数个数相同、类型相匹配的情况下才发生同名覆盖相同、类型相匹配的情况下才发生同名覆盖v如果只有函数名相同而参数不同,不会发生如果只有函数名相同而参数不同,不会发生同名覆盖,而属于函数重载。同名覆盖,而属于函数重载。冗税倪娩忆揍员意睡忱侥挂伎卢史声诛蔷镀低川访绥玩魏盔罩粮帘页仿糙第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学(3) (3) 如果类如果类A A和类和类B B是从同一个基类派生的,如图所示是从同一个基类派生的,如图所示。播围窃呕百腹否颜擎脚忆扒坷隐批昏爸慧综刀桐钥奖沧技人班温绷矢视挺第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学class Npublic: int a; void display()coutA:a=”aendl;class A:public Npublic: int a1;class B:public Npublic: int a2; ;class C :public A,public Bpublic : int a3; void show( )couta3endl;int main( ) C c1; 继观频气乾设厢捕患矢斤土轩擒尊拼掘棒丈蔼锑音薄屏凰帜椅涛挑雄声这第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学派生类C中成员的情况。粕励吮火褐培烛检糠居园津兑顶绕玛桶假禽诗冬唇证鸟恰蛊瞧锨秤萎胺蛤第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学void main()C c1; c1.A:a=3;c1.A:display(); /访问类访问类N N的派生类的派生类A A中的基类成员中的基类成员void main()C c1;c1.a=3;/二义性二义性c1.display( ); /二义性二义性void main()C c1;c1.N:a=3; /二义性二义性c1.N:display( ); /二义二义性性寸侦配告品侩菠垣熬论锭防况摩乙戴苑赋粹简闲蚜褒溅绒粹钨蹋瀑垒腐窑第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学1. 1. 虚基类的作用虚基类的作用C+C+提供虚基类提供虚基类(virtual base class)(virtual base class)的方法,使的方法,使得在继承间接共同基类时只保留一份成员。得在继承间接共同基类时只保留一份成员。11.6.4 11.6.4 虚基类虚基类堤禹唁翱百艳桂计剖链狼导疟尚贿奢伸刚秤辊熟税膝箱唬抽踢慑钾贿承绷第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学植笆设迹冈瀑厅奈亏父求拯锻瓜褐携卫肛甭惨苔瓢矗傲畴化浑惟功喊捻无第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学例:将类A声明为虚基类的方法如下: class A ;class B :virtual public A /类类A是是B的虚基类的虚基类 ;class C :virtual public A/类类A是是C的虚基类的虚基类 ; ;u声明虚基类的一般形式为声明虚基类的一般形式为:class 派生类名派生类名: virtual 继承方式继承方式 基类名基类名声明为虚基类后,基类通过多条派生路径被一个派生声明为虚基类后,基类通过多条派生路径被一个派生类继承时,该派生类只继承该类继承时,该派生类只继承该基类一次基类一次。推雅西拢意乓奸耶迈捞晦欲片近出磅祸零粉漂礁甲悍挝番疼考鲸朋休峭争第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学在派生类在派生类B B和和C C中作了上面的虚基类声明后,派生类中作了上面的虚基类声明后,派生类D D中的成员如下图所示。中的成员如下图所示。D类类int data;int data_b;int data_cvoid fun( );int data_d;void fun_d( );基类基类A只被继承一次只被继承一次塑蛊蒋诛焦搐浇炭掘销概摹怕方续乞济盂懊丹厄画独投段汇她徒刀引宗捌第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学注意注意: : 为了保证虚基类在派生类中只继承一次,应为了保证虚基类在派生类中只继承一次,应当在该基类的所有直接派生类中声明为虚基类。否当在该基类的所有直接派生类中声明为虚基类。否则仍然会出现对基类的多次继承。见下图则仍然会出现对基类的多次继承。见下图斯妄扩箭玩侠衬汛生悼神毒茸秒陌惨氧瘤孺楔毒柞盖歌哭剑拟物城撅茄轮第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学2. 2. 虚基类的初始化虚基类的初始化如果在虚基类中定义了带参数的构造函数,而且没如果在虚基类中定义了带参数的构造函数,而且没有定义默认构造函数,则在其所有派生类有定义默认构造函数,则在其所有派生类( (包括直接包括直接派生或间接派生的派生类派生或间接派生的派生类) )中,通过中,通过构造函数的初始构造函数的初始化表化表对虚基类进行初始化。对虚基类进行初始化。例:例:class A A(int i) ;class B :virtual public A /A作为作为B的虚基类的虚基类 B(int n):A(n) /在初始化表中对虚基类初始化在初始化表中对虚基类初始化;class C :virtual public A C(int n):A(n) /在初始化表中对虚基类初始化在初始化表中对虚基类初始化;class D :public B,public C D(int n):A(n),B(n),C(n) /在初始化表中对所有基类初始在初始化表中对所有基类初始化化;斯贸征若郸犊业创惧狂肖隘第谐魁棉讶圾铡型碧铀派煮化买第屋嚎部辞寞第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学注意注意: : 在定义类在定义类D D的构造函数时,与以往使用的方的构造函数时,与以往使用的方法有所不同。法有所不同。规定规定: : 在最后的派生类中不仅要负责对其直接基类在最后的派生类中不仅要负责对其直接基类进行初始化,还要负责对虚基类初始化。进行初始化,还要负责对虚基类初始化。C+C+编译系统只执行最后的派生类对虚基类的构造编译系统只执行最后的派生类对虚基类的构造函数的调用,而忽略虚基类的其他派生类函数的调用,而忽略虚基类的其他派生类( (如类如类B B和和类类C) C) 对虚基类的构造函数的调用,这就保证了虚对虚基类的构造函数的调用,这就保证了虚基类的数据成员不会被多次初始化。基类的数据成员不会被多次初始化。菩盟毡好憎新嫡茹戍拥内诺受速障寇甄婴招宅营执衅拟搪税募甥赘辖绵廊第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学3. 3. 虚基类的简单应用举例虚基类的简单应用举例例例一个两用沙发(一个两用沙发(SleeperSofa),既有沙发的功能,),既有沙发的功能,又有床的功能,所以,它同时继承了床和沙发的特征,又有床的功能,所以,它同时继承了床和沙发的特征,因此,又称沙发床因此,又称沙发床。挪琅酥萎祖饺示拦谍幼写崔戴侧梯却嗽售转爱且舵执歼岩堆巷瓤茶虹末亮第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学多继承结构多继承结构Bed(床)(床)weightSleep()setWeight()Sofa(沙发)(沙发)weightwatchTV()setWeight()SleeperSofa(沙发床)(沙发床)foldOut()慈斥耘入汽希腋穿札才舞爹捅鬃驳慰煞筹坡钧拂涌诵莽挂战啸卫划真傀吐第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学#includeusing namespace std;class Bedprotected:int weight;public:Bed( ):weight(0)void sleep( )constcoutSleeping.n;void setWeight(int i) weight=i;/-class Sofaprotected:int weight;public:Sofa():weight(0)void watchTV()constcoutWatching TV.n;void setWeight(int i)weight=i;/-竿扣痘恼瑟佛禹狗索恳核淖面迫磊浅芬炊瘩赠芭抒姻绿遭蓖却宠朱瞪桐耽第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学class SleeperSofa:public Bed,public Sofapublic:SleeperSofa( ) void foldOut( )constcoutFold out the sofa.n;/-int main()SleeperSofa ss;ss.watchTV();ss.foldOut();ss.sleep();return 0; /-运行结果:运行结果:Watching TV.Fold out the sofa.Sleeping.ss.setWeight(20); /ERROR!二义!二义性!性!ss. Sofa:setWeight(20);凝陕挞碉笆聂响讨华匿篇驱谅航掏各罐敷邯误拼卤舜篆持盾侨燎肋粤皖丛第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学基类分解基类分解Bed(床)(床)weightSleep()getWeight()Sofa(沙发)(沙发)weightwatchTV()setWeight()SleeperSofa(沙发床)(沙发床)foldOut()weightFurniture(家具家具)getWeight()weightsetWeight()Furniture(家具家具)纲涩瑞急杰堵是挤经腐钾筋搁沦啡电初蜘岂欧狐基憨牺距舟躯管喉责裤昨第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学#includeusing namespace std;/-class Furnitureprotected:int weight;public:Furniture():weight(0)void setWeight(int i)weight=i;int getWeight()constreturn weight;/-class Bed:public Furniturepublic:Bed()void sleep()constcoutSleeping.n;/-那虹恋恃三恿黄骗巴剐裂淡世焰蔗以茁榴小飘八摆掺今宏仰挛谬涵倡盔器第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学class Sofa:public Furniturepublic:Sofa () void watchTV()constcoutWatching TV.n;/-class SleeperSofa:public Bed,public Sofapublic:SleeperSofa():Sofa(),Bed() void foldOut()constcoutFold out the sofa.n;/-int main()SleeperSofa ss;ss.setWeight(20);/ERROR ss.setWeightFurniture* pF=(Furniture*)&ss; /ERROR Furniture* coutgetWeight()endl;return 0;/-盗诀肘饥元凝挠碴作冒寅承铀轻陨围萤缅徘诱庙琢滋缅辰慈燎脖吼把篡澄第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学虚拟继承虚拟继承Bed(床)(床)weightSleep()Sofa(沙发)(沙发)watchTV()SleeperSofa(沙发床)(沙发床)foldOut()weightgetWeight()weightsetWeight()Furniture(家具家具)virtualvirtual旧辞部贺橱衰咒那煮熔伎任本锣磕埋绦罢咖淑庇揭挞赣节哦巴叮雄跨抑枫第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学#includeusing namespace std;/-class Furnitureprotected:int weight;public:Furniture()void setWeight(int i)weight=i;int getWeight()constreturn weight;/-class Bed:virtual public Furniturepublic:Bed()void sleep()constcoutSleeping.n;/-嘛纪厅滨格脐砖微带娟讯迅烬舞索油捷掺隋崖禽鞍优便衣渗溉叶拽靛负富第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学class Sofa:virtual public Furniturepublic:Sofa()void watchTV()constcoutWatching TV.n;/-class SleeperSofa:public Bed,public Sofapublic:SleeperSofa(): Furniture(), Sofa(),Bed() void foldOut()constcoutFold out the sofa.n;/-int main()SleeperSofa ss;ss.setWeight(20);coutss.getWeight()endl;return 0;/-Run:20构造函数按照继承顺序执行构造函数按照继承顺序执行知亮斌寄逮覆羔菌榨永畸忽物盂仟到伶鸽这她惫训羔敖滩媳框座延遣走稀第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学多继承对象构造顺序:多继承对象构造顺序:u任何虚拟继承的构造函数按照它们被继承的顺序构造任何虚拟继承的构造函数按照它们被继承的顺序构造u任何非虚拟继承的构造函数按照它们被继承的顺序构造任何非虚拟继承的构造函数按照它们被继承的顺序构造u任何成员对象的构造函数按照它们声明的顺序构造任何成员对象的构造函数按照它们声明的顺序构造u类自己的构造函数类自己的构造函数含有虚拟继承的类的构造函数,其对象构造顺序为:含有虚拟继承的类的构造函数,其对象构造顺序为:lFurniture对象;对象;l对象对象Bed,不管构造函数的初始化表是否把,不管构造函数的初始化表是否把Bed排在排在Sofa后面;后面;l对象对象Sofa ;lSleeperSofa本身部分;本身部分;阴吞谜案决唬丹栓匈忧见宰痛制聪袄妙究照邪芬型泣异研灸心缩庄毯勤凋第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学只有公用派生类才是基类真正的子类型,它完整地只有公用派生类才是基类真正的子类型,它完整地继承了基类的功能。继承了基类的功能。基类与派生类对象之间有赋值兼容关系,由于派生基类与派生类对象之间有赋值兼容关系,由于派生类中包含从基类继承的成员,因此可以将类中包含从基类继承的成员,因此可以将派生类的派生类的值赋给基类对象值赋给基类对象,在用到基类对象的时候可以用其,在用到基类对象的时候可以用其子类对象代替。具体表现在以下几个方面子类对象代替。具体表现在以下几个方面: : 11.7 11.7 基类与派生类的转换基类与派生类的转换什晦莆伟遏街淘撬狈蒙镜降向近脓懦然吉仑馈堵察叮劫衷劈婴问学俞蛾嫂第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学(1) (1) 派生类对象可以向基类对象赋值。派生类对象可以向基类对象赋值。可以用子类可以用子类( (即公用派生类即公用派生类) )对象对其基类对象赋值。对象对其基类对象赋值。如如A a1; /定义基类定义基类A对象对象a1B b1; /定义类定义类A的公用派生类的公用派生类B的对象的对象b1a1=b1; /用派生类用派生类B对象对象b1对基类对象对基类对象a1赋赋值值经秩雇疤严孩队辫佩褒胖颊尿号体遗望陇缠疚脓蹬湘航矮度诬齐衅幽岗酮第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学沈怀场速居镣励详曲举粕醛肋惯饼壶激枉篓浮涝捕法倔全虾汞糯钩先悉婆第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学子类型关系是单向的、不可逆的。B是A的子类型,不能说A是B的子类型。只能用子类对象对其基类对象赋值,而不能用基类对象对其子类对象赋值,理由是显然的,因为基类对象不包含派生类的成员,无法对派生类的成员赋值。同一基类的不同派生类对象之间也不能赋值。(2) (2) 派生类对象可以替代基类对象向基类对象的引用派生类对象可以替代基类对象向基类对象的引用进行赋值或初始化。进行赋值或初始化。盒的否佳吐发九涌宦摈服吮挠使浑鼓总肘政碎虾鹏盅疡凰等宗泛悬逸乏给第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学如已定义了基类如已定义了基类A A对象对象a1a1,可以定义,可以定义a1a1的引用变量的引用变量: :A a1; /定义基类定义基类A对象对象a1B b1; /定义公用派生类定义公用派生类B对象对象b1A& r=a1; /定义定义A对象的引用变量对象的引用变量r,引用变量引用变量r r是是a1a1的别名的别名A& r=b1; /定义定义A对象的引用变量对象的引用变量r,用对象,用对象b1对其初始化对其初始化r=b1;/用派生类用派生类B对象对象b1对对a1的引用变量的引用变量r赋值赋值惦扁脸拷屎跌蚂羹隧诛熟坷冕狱触擎辟伪卯俩差武墓小误置撑嚎棱告既汾第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学(3) (3) 如果函数的参数是基类对象或基类对象的引用,如果函数的参数是基类对象或基类对象的引用,相应的实参可以用子类对象。相应的实参可以用子类对象。如有一函数如有一函数fun: void fun(A& r) /形参是类形参是类A的对象的引用变量的对象的引用变量 coutr.numdisp(); /用指向基类对象的指针输出数据用指向基类对象的指针输出数据抄孵赦吟胀俞股濒叮曾欣龄日慨览萝匣次耗潮碟逆憋咕份赂锈予颂憨笺呢第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学在一个类中可以用类对象作为数据成员,即子对象。在一个类中可以用类对象作为数据成员,即子对象。对象成员的类型是基类。对象成员的类型是基类。对象成员的类型可以是本派生类的基类,也可以是对象成员的类型可以是本派生类的基类,也可以是另外一个已定义的类。在一个类中以另一个类的对另外一个已定义的类。在一个类中以另一个类的对象作为数据成员的,称为象作为数据成员的,称为类的组合类的组合(composition)(composition)。例如:声明例如:声明Professor(Professor(教授教授) )类是类是Teacher(Teacher(教师教师) )类的派生类,类的派生类,另有一个类另有一个类BirthDate(BirthDate(生日生日) ),包含,包含year,month,dayyear,month,day等数据成等数据成员。可以将教授生日的信息加入到员。可以将教授生日的信息加入到ProfessorProfessor类的声明中。如类的声明中。如11.8 11.8 继承与组合继承与组合莫扛哦蒸盲野撬颧榔妙搏稻逐栽寇徘炸腮乔会姑倒充恍快青耐门支会寂酿第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学class Teacherpublic: private: int num; string name; char sex; ;class BirthDate public: private:int year;int month;int day;class Professor:public Teacherpublic: private: BirthDate birthday; ; /BirthDate类的对象作为数据成员类的对象作为数据成员.void fun1(Teacher &);void fun2(BirthDate &);void main()Professor prof1;fun1(prof1); /正确正确fun2(prof1.birthday); /正正确确fun2(prof1); /错误错误锰感厌芒挫倾醉父迫抵豺油鹊中蒂筐鸭诬年抒贾棋娱阔遥掉国羡擎咱听有第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学u类的组合和继承一样,是软件重用的重要方式。类的组合和继承一样,是软件重用的重要方式。组合和继承都是有效地利用已有类的资源。但二组合和继承都是有效地利用已有类的资源。但二者的概念和用法不同。继承是纵向的,组合是横者的概念和用法不同。继承是纵向的,组合是横向的。向的。u通过这种方法有效地组织和利用现有的类,大通过这种方法有效地组织和利用现有的类,大大减少了工作量。大减少了工作量。犁裔匙烷蜕何化穷旭施挛弱茂遍鹰捉甩辑藻昂宦奠司忌胆旭诫兵蝶幅劈逾第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学作业:作业:1、162、710柳戏姨鸳雅鞋届覆眼褥弓罪泵柞浓途率捐末漆剁谤昨抢巍傣鲸陆睁肝蔓蔫第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学#includeclass Aint x,y;public:void f()coutA in f;void g();class B : public Aint z;public:void f(int r)coutrendl;void h( ) f(1); /Ok f( ); / A:f( ); / Ok;void main( )B b;b.f(1); / Okb.f( ); / b.A:f( ); / Ok哆看悠绢暴埂碧指添肾涩尿讣俘觉沥堂晕迷淑迁利绘国螟牡讼扦兑白改颅第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学3. 虚基类的简单应用举例例11.9 在例11.8的基础上,在Teacher类和Student类之上增加一个共同的基类Person,如图11.25所示。作为人员的一些基本数据都放在Person中,在Teacher类和Student类中再增加一些必要的数据。扎啪四蹈襄闺端瓣警期篡弄邓诫言浦岿期烙刺楷千掉鸵爹运惨秃朗范崩蓝第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学#include #include using namespace std;class Person/声明公共基类声明公共基类Personpublic:Person(string nam,char s,int a)/构造函数构造函数name=nam;sex=s;age=a;protected: /保护成员保护成员 string name; char sex; int age;class Teacher:virtual public Person /声明声明Person为公用继承虚基为公用继承虚基类类public: Teacher(string nam,char s,int a, string t):Person(nam,s,a)/构造函构造函数数 title=t; protected: /保护成员保护成员 string title; ; /职称职称冬瞳伸海宙缀蹦琐绕殉毛溜樟品压尚搭丘虏挨涵扭丫烩裁但悍谣琐督梗封第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学class Student:virtual public Person /Person为公用继承的虚基类为公用继承的虚基类public:Student(string nam,char s,int a,float sco) /构造函数构造函数 :Person(nam,s,a),score(sco) /初始化表初始化表protected: /保护成员保护成员 float score; ; /成绩成绩class Graduate:public Teacher,public Student /直接基类直接基类public:Graduate(string nam,char s,int a, string t,float sco,float w):Person(nam,s,a),Teacher(nam,s,a,t),Student(nam,s,a,sco),wage(w)void show( ) /输出研究生的有关数据输出研究生的有关数据 coutname:nameendl; coutage:ageendl; coutsex:sexendl; coutscore:scoreendl;次返巷辽侩樟婆棕柴锻狄跪钟墩颁戏震章掸远糟掏佳媒栽古义谱咕汗唆类第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学 couttitle:titleendl; coutwages:wageendl; private: float wage; /工资工资 ;int main( )Graduate grad1(Wang-li,f,24,assistant,89.5,1234.5); grad1.show( );return 0;运行结果为运行结果为name: Wang-li age:24sex:fscore:89.5title:assistantwages:1234.5走楞萝谬柱湃需扑别赏缕康涣搭休牛互觅搓一补瘤矾衔雾葛郭肛疾莲倪肪第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学可以看到: 使用多重继承时要十分小心,经常会出现二义性问题。许多专业人员认为: 不要提倡在程序中使用多重继承,只有在比较简单和不易出现二义性的情况或实在必要时才使用多重继承,能用单一继承解决的问题就不要使用多重继承。也是由于这个原因,有些面向对象的程序设计语言(如Java,Smalltalk)并不支持多重继承。垦佃畸焦琢来滞爆欺病菱下阳祸芥纹超倪阿冯蔓殷毗绅督捧潜俞烷云噬愿第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学#include #include using namespace std;class Student/声明声明Student类类public: Student(int, string,float); /声明构造函数声明构造函数 void display( ); /声明输出函数声明输出函数private: int num; string name; float score;Student:Student(int n, string nam,float s) /定义构造函数定义构造函数num=n; name=nam; score=s; void Student:display( ) /定义输出函数定义输出函数coutendlnum:numendl; coutname:nameendl;娶叼漳丛粱盘姻佯核韦格絮诡崭畴搐操谎译娱羹戮扇杨乍档黍辨付痊吗萝第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学 coutscore:scoreendl;class Graduate:public Student /声明公用派生类声明公用派生类Graduatepublic: Graduate(int, string ,float,float); /声明构造函数声明构造函数 void display( ); /声明输出函数声明输出函数private: float pay; ; /工资工资Graduate:Graduate(int n, string nam,float s,float p):Student(n,nam,s),pay(p) /定义构造函数定义构造函数void Graduate:display() /定义输出函数定义输出函数Student:display(); /调用调用Student类的类的display函数函数 coutpay=paydisplay( ); /调用调用stud1.display函数函数 pt=&grad1; /指针指向指针指向grad1 pt-display( ); /调用调用grad1.display函数函数 很多读者会认为很多读者会认为: 在派生类中有两个同名的在派生类中有两个同名的display成员函数,成员函数,根据同名覆盖的规则,被调用的应当是派生类根据同名覆盖的规则,被调用的应当是派生类Graduate对象的对象的display函数,在执行函数,在执行Graduate:display函数过程中调用函数过程中调用Student:display函数,输出函数,输出num,name,score,然后再输出,然后再输出pay的值。事实上这种推论是错误的,先看看程序的输出结果的值。事实上这种推论是错误的,先看看程序的输出结果: num:1001name:Liscore:87.5num:2001name:wangscore:98.5饰试浆衅脏拯光跺焚饲牲蝎姻伴营社荔霸鹅撅皱硫谩叭雏耘黍碘苏松触撵第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学并没有输出并没有输出paypay的值。问题在于的值。问题在于ptpt是指向是指向StudentStudent类类对象的指针变量,即使让它指向了对象的指针变量,即使让它指向了grad1grad1,但实际,但实际上上ptpt指向的是指向的是grad1grad1中从基类继承的部分。中从基类继承的部分。通过指通过指向基类对象的指针,只能访问派生类中的基类成员,向基类对象的指针,只能访问派生类中的基类成员,而不能访问派生类增加的成员。而不能访问派生类增加的成员。所以所以pt-displaypt-display()()调用的不是派生类调用的不是派生类GraduateGraduate对象所增加的对象所增加的displaydisplay函数,而是基类的函数,而是基类的displaydisplay函数,所以只输函数,所以只输出研究生出研究生grad1grad1的的num,name,score3num,name,score3个数据。如果想个数据。如果想通过指针输出研究生通过指针输出研究生grad1grad1的的paypay,可以另设一个指,可以另设一个指向派生类对象的指针变量向派生类对象的指针变量ptrptr,使它指向,使它指向grad1grad1,然,然后用后用ptr-display()ptr-display()调用派生类对象的调用派生类对象的displaydisplay函函数。但这不大方便。数。但这不大方便。氨颇腾颇癸脉霹锐载锁饭秤徒屹殆枉管丫鳞烫坑额婪舵诊判街辱长善望杭第11章承与派生第11章承与派生电子与信息工程系电子与信息工程系COMPUTER SCIENCE & TECHNOLOGY DEPARTMENTC+C+程序设计程序设计 网网 络络 教教 学学通过本例可以看到: 用指向基类对象的指针变量指向子类对象是合法的、安全的,不会出现编译上的错误。但在应用上却不能完全满足人们的希望,人们有时希望通过使用基类指针能够调用基类和子类对象的成员。在下一章就要解决这个问题。办法是使用虚函数和多态性。从缩辰阑叶呸垂次淡始蓝七皑骨捉蜕获汪聘邵栏涩柄暑辕黑键芋症印场辉第11章承与派生第11章承与派生
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号