第8章继承与组合_第1页
第8章继承与组合_第2页
第8章继承与组合_第3页
第8章继承与组合_第4页
第8章继承与组合_第5页
已阅读5页,还剩44页未读 继续免费阅读

下载本文档

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

文档简介

第8章继承与组合C++语言程序设计中山大学信息科学与技术学院2主要内容继承的相关概念C++中的继承组合-has-a关系多重继承重复继承31、继承的相关概念使用继承来构成概念的层次结构在事物分类方法上常用继承描述的是IS-A关系:苹果是一种水果水牛是一种牛跑车是一种小汽车继承中的“父”与“子”“父”具有一般性“子”在继承“父”的特性的基础上,增加了自己的特殊性41、继承的相关概念(续)面向对象程序设计中的继承(inheritance)机制在(一个或几个)现有类的基础上经过适当修改、扩充而构成新的类使我们能够定义类对类型之间的关系建模共享公共的东西而仅特别指明不同的东西52.C++中的继承基本概念基类:被继承者派生类:继承者祖先类后代类在类B中除了自己定义的成员之外,还自动包括了类A中定义的数据成员与成员函数,这些自动继承下来的成员称为类B的继承成员

A

B

基类(Baseclass)

派生类(Derivedclass)

62.C++中的继承(续)继承的作用作为类的构造机制用户通过对现有类的修改、扩充来构造出新类作为类型的构造机制所有需要基类对象的地方都可以接受派生类对象

7C++支持的继承形式单重继承多重继承重复继承2.C++中的继承(续)

AB

一个派生类只有一个基类

A

B

C

一个派生类有两个或两个以上直接基类

D

派生类两次或两次以上重复继承某个祖先类

多重继承

重复继承

单重继承

ABC82.C++中的继承(续)继承成员的访问控制派生类B在继承了基类A后,B或其他类是否可以访问B中的继承成员?类A中成员的访问控制方式类B在继承类A时指定的继承访问控制方式92.C++中的继承(续)基类A中成员的访问控制方式继承控制方式派生类B中继承成员的访问控制publicpublicpublicprotectedprotectedprivate不可访问publicprotectedprotectedprotectedprotectedprivate不可访问publicprivateprivateprotectedprivateprivate不可访问102.C++中的继承(续)继承的语法

class

派生类名:基类名列表

{

数据成员和成员函数声明

};

其中基类名列表的语法:继承控制方式基类名1,继承控制方式基类名2,…,继承控制方式基类名n11//accessControl.cpp--演示在继承中派生类对基类成员的访问控制classBase{public: intgetBaseI(){ BaseTemp=BaseI; returnBaseI; };//公有成员函数protected: intBaseI;//受保护成员private: intBaseTemp;//私有成员};//公有派生,在Derived1类中,BaseI是受保护成员,getBaseI()是公有成员,//BaseTemp不可访问classDerived1:publicBase{public: intgetDrv1I(){//编译出错,因为从Base继承下来的BaseTemp不可访问

BaseTemp=BaseI; returnBaseI; }};12//受保护派生:在Derived2类中,BaseI是受保护成员,getBaseI()变成受//保护成员,BaseTemp不可访问classDerived2:protectedBase{public: intgetDrv2I(){ //编译出错,因为从Base继承下来的BaseTemp不可访问

BaseTemp=BaseI; returnBaseI; }};//私有派生:在Derived3类中,BaseI,getBaseI()都变成私有成员,//BaseTemp不可访问classDerived3:privateBase{ public: intgetDrv3I(){//编译出错,因为从Base继承下来的BaseTemp不可访问

BaseTemp=BaseI; returnBaseI;}};13intmain(){ Derived1drv1; Derived2drv2; Derived3drv3;//getBaseI()在Derived1类中是公有成员

drv1.getBaseI(); //编译错:在Derived2类中,getBaseI()变成受保护成员,外部不可访问

drv2.getBaseI(); //编译错:在Derived3类中,getBaseI()变成了私有成员,外部不可访问

drv3.getBaseI(); return0;}142.C++中的继承(续)继承实例小汽车类和跑车类P.190,程序清单8-2电话号码类和国际电话号码类P.192,程序清单8-3CarSportCarPhoneInternPhone增加“颜色”属性及相关操作增加“国家代码”属性及相关操作152.C++中的继承(续)派生类中继承成员函数的重定义目的基类中的函数不能满足派生类的特殊要求,需要解决派生类的特殊性如程序清单8-3:InternPhone类继承了Phone类,增加了特殊的属性countryCode.从Phone类继承的成员函数write无法满足InternPhone的输出要求,因此需要在InternPhone中重新定义write函数方法在派生类中定义一个函数原型和继承成员函数完全一样的成员函数162.C++中的继承(续)派生类中继承成员函数的重定义(续)编译器对成员函数调用的处理首先在派生类中查找该函数的定义,找到则调用,否则:在基类中查找该函数的定义,找到则调用,否则:继续在上层类中查找,找到则调用。如果查找完所有的祖先类都没有找到该函数的定义,则报未定义错例:程序清单8-3中,myFriendPhone.write()调用的是InternPhone类中重定义的继承成员函数write172.C++中的继承(续)继承层次中的构造函数和析构函数派生类对象的存贮空间存放从基类继承的非静态数据成员存放派生类中定义的非静态数据成员例Carcar(100,100);SportCarsportCar(100,200,"black")。200100weightspeedcar100200“black”weightspeedcolorsportCar可视为基类子对象182.C++中的继承(续)继承层次中的构造函数和析构函数(续)基类的构造函数和析构函数不被继承派生类必须定义自己的构造函数和析构函数在生成派生类对象时,由派生类的构造函数调用它的直接基类的构造函数,对从基类继承来的数据成员进行初始化192.C++中的继承(续)继承层次中的构造函数和析构函数(续)派生类的构造函数作用通过初始化列表给基类的构造函数传递参数,初始化基类的数据成员初始化派生类中定义的数据成员带初始化列表的构造函数的语法形式派生类名(形参表):基类名(传递给基类构造函数的实参表)20例:

SportCar类的构造函数为:SportCar(inttheWeight,inttheSpeed,stringtheColor):Car(theWeight,theSpeed){color=theColor;}

则语句SportCarsportCar(100,200,"black");通过初始化列表Car(theWeight,theSpeed)向Car类的构造函数传递参数theWeight,theSpeed,值分别为100,200,调用Car类的构造函数将派生类从基类中继承的数据成员weight初始化为100,speed初始化为200由SportCar类的构造函数将该类中定义的数据成员color初始化为"black"21例:InternPhone类的默认构造函数为:InternPhone::InternPhone(){countryCode="";}则语句InternPhonemySisterPhone;调用基类Phone的默认构造函数将派生类从基类中继承的数据成员areaCode初始化为"",number初始化为"",type初始化为HOME由InternPhone类的构造函数将该类定义的数据成员countryCode初始化为""222.C++中的继承(续)继承层次中的构造函数和析构函数(续)构造函数和析构函数的调用次序创建派生类对象时,构造函数的调用次序是:直接基类的构造函数派生类的构造函数如果继承的层次较多时,根据以上规则,可以推导出:在创建一个后代类对象时,需要回溯到它的最远祖先,由最远祖先开始逐级调用构造函数初始化该后代类继承得到的数据成员,最后再调用后代类自己的构造函数。析构函数的调用次序与构造函数的相反23//constructorAndDestrutorInInheritance.cpp//演示多层次继承中构造函数和析构函数的调用次序#include<iostream>usingnamespacestd;classBase{public: Base()//构造函数

{ cout<<"ConstructingBaseobject.\n"; } ~Base()//析构函数

{ cout<<"DestructingBaseobject.\n"; }};classDerivedLevel1:publicBase{public: DerivedLevel1()//构造函数

{ cout<<"ConstructingDerived_level_1object.\n";} ~DerivedLevel1()//析构函数

{ cout<<"DestructingDerived_level_1object.\n";}};24classDerivedLevel2:publicDerivedLevel1{public: DerivedLevel2()//构造函数

{ cout<<"ConstructingDerived_level_2object.\n"; } ~DerivedLevel2()//析构函数

{ cout<<"DestructingDerived_level_2object.\n"; }};intmain(){ DerivedLevel2obj; //声明一个后代类的对象

return0;//什么也不做,仅完成对象obj的创建与撤销}25上述程序中各类的继承层次关系:DerivedLevel1DerivedLevel2Base26程序的运行结果:ConstructingBaseobject.ConstructingDerived_level_1object.ConstructingDerived_level_2object.DestructingDerived_level_2object.DestructingDerived_level_1object.DestructingBaseobject.

27定义包含其他类对象的类描述类之间的HAS-A(有一个)关系整体与部分的关系例:汽车有轮子空调育压缩机表示方法:使用成员对象(嵌入对象)例:3.组合28表示方法:使用成员对象(嵌入对象)例:classWheel{... //成员定义省略};classCar{public:... //其他成员定义省略private:intweight;intspeed;

Wheelwheels[4];//一个Car对象中包含4个Wheel对象};3.组合(续)SportCar

Car

Wheel

293.组合(续)组合与构造函数和析构函数构造函数的调用次序是:按类声明中嵌入对象出现的次序调用嵌入对象的构造函数执行本类的构造函数当一个类既是派生类同时又包含嵌入对象时,构造函数调用次序:调用基类的构造函数按类声明中嵌入对象出现的次序调用嵌入对象的构造函数执行派生类的构造函数通过初始化列表向嵌入对象的构造函数传递参数:

嵌入对象名1(实参表1),嵌入对象名2(实参表2),…30//constructorAndDestructorInComposition.cpp//演示组合及派生关系中构造函数和析构函数的调用次序#include<iostream>usingnamespacestd;classC{public: C()//构造函数

{ cout<<"ConstructingCobject.\n";} ~C()//析构函数

{ cout<<"DestructingCobject.\n";}};classBase{public: Base()//构造函数

{ cout<<"ConstructingBaseobject.\n"; } ~Base()//析构函数

{ cout<<"DestructingBaseobject.\n"; }};classDerived:publicBase{public: Derived()//构造函数

{ cout<<"ConstructingDerivedobject.\n"; } ~Derived()//析构函数

{ cout<<"DestructingDerivedobject.\n"; }private:C mObj;//嵌入对象};intmain(){ Derivedobj; //声明一个派生类的对象

//什么也不做,仅完成对象obj的创建与撤销

return0;}31classDerived:publicBase{public: Derived()//构造函数

{ cout<<"ConstructingDerivedobject.\n"; } ~Derived()//析构函数

{ cout<<"DestructingDerivedobject.\n"; }private:

C mObj;//嵌入对象};intmain(){ Derivedobj; //声明一个派生类的对象

return0;//什么也不做,仅完成对象obj的创建与撤销}32程序运行结果:ConstructingBaseobject.ConstructingCobject.ConstructingDerivedobject.DestructingDerivedobject.DestructingCobject.DestructingBaseobject.333.组合(续)组合的实例:P.202,程序清单8-6

使用程序清单8-3定义的InternPhone类,组合定义类contactInfo,在contactInfo类中包括姓名,email地址,和电话号码(homePhone,officePhone,faxPhone,cellPhone)

ContactInfo

InternPhone

Phone

34继承与组合的比较继承描述“一般与特殊”关系:子类是一种特殊的父类,子类对象是特殊的父类对象组合描述“整体与部分”关系:一个对象是另一个对象的组成部分354.多重继承描述“既是一种…又是一种…”的类关系例:classA{…};classB{…};classC:publicA,publicB{…};派生类C具有两个基类(类A和类B),在C类对象的存储空间中既存放C类中定义的非静态数据成员,也存放了从类A和类B继承而来的非静态数据成员364.多重继承(续)多重继承下派生类的构造函数派生类名(形参表):

初始化列表{

函数体语句}如果派生类调用基类中的默认构造函数,则初始化列表为空如果不为空,则初始化列表的语法为:基类名1(实参表1),基类名2(实参表2),…其中各实参表中的参数来自派生类名后的参数表374.多重继承(续)创建派生类对象时构造函数的执行顺序:先执行所有基类的构造函数再执行派生类本身构造函数注意:处于同一层次的各基类构造函数的执行顺序取决于定义派生类时所指定的各基类顺序384.多重继承(续)多重继承的名字冲突问题名字冲突(nameclash):当两个以上基类具有名字相同的成员时,在派生类中这个名字会产生二义性,即:编译程序无法确定派生类的对象使用该名字时应使用哪个基类中的版本解决方式用作用域运算符明确指明使用那个基类的成员在派生类中重定义有名字冲突的成员39classBase1{public: voidshow(){cout<<i<<"\n";}protected: inti;};classBase2{public: voidshow(){ cout<<j<<"\n";}protected: intj;};//多重继承引起名字冲突:Derived的两个基类Base1和//Base2有相同的名字showclassDerived:publicBase1,publicBase2{public: voidset(intx,inty) {i=x; j=y; }};//派生类在编译时不出错:C++并不禁止名字冲突的产生[例1]40intmain(){ Derivedobj; //声明一个派生类的对象

obj.set(5,7); //set()是Derived类自身定义的

//obj.show(); //二义性错误,编译程序无法决定调用哪一个版本

obj.Base1::show(); //显式地调用从Base1继承下来show() obj.Base2::show(); //显式地调用从Base2继承下来show() return0;}41[例2]classDerived:publicBase1,publicBase2{public: voidset(intx,inty){i=x;j=y; }

voidshow() {cout<<i<<"\n";cout<<j<<"\n";}};

intmain(){ Derivedobj; //声明一个派生类的对象

obj.set(5,7); //set()是Derived类自身定义的

obj.show(); //无二义性问题,调用的是Derived中新定义的版本

obj.Base1::show(); //仍然可调用从Base1继承下来show() obj.Base2::show(); //仍然可调用从Base2继承下来show() return0;}425.重复继承当派生类的多个基类具有相同的祖先时,会出现重复继承的情形由多重继承导致

BaseBase1DerivedBase2435.重复继承(续)Derived类对象的存储空间中会包含Base类中非静态数据成员的两个副本,存在二义性问题解决方法:使用作用域运算符::明确选择的是哪个副本使用虚基类方法,使派生类的存储空间中只保留一个副本44//virtualBaseDemo.cpp//演示多重继承中虚基类的使用//祖先类classBase{public:voidsetData(intnewData) { data=newData;}protected:intdata;};//基类1,Base是其虚基

温馨提示

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

评论

0/150

提交评论