《面向对象程度设计基础(第2版)》第七章继承机制_第1页
《面向对象程度设计基础(第2版)》第七章继承机制_第2页
《面向对象程度设计基础(第2版)》第七章继承机制_第3页
《面向对象程度设计基础(第2版)》第七章继承机制_第4页
《面向对象程度设计基础(第2版)》第七章继承机制_第5页
已阅读5页,还剩25页未读 继续免费阅读

下载本文档

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

文档简介

第七章

继承机制

继承机制的作用继承成员的访问控制规则继承成员的调整类型兼容性类层次中的构造函数与析构函数多重继承重复继承

§7.1继承机制

一、继承继承是类与类之间的一种关系定义:“类B继承类A”,

或者说“类A派生类B”

图解为:

则在类B中除了自己定义的成员之外,还自动包括了类A中定义的数据成员与成员函数,这些自动继承下来的成员称为类B的继承成员。

AB基类派生类二、继承的语法

1.继承的语法:class派生类名:基类类名表{

public:

公有成员说明列表;

protected:

受保护成员说明列表;

private:

私有成员说明列表;};其中基类类名表的格式为:

access基类类名1,……,access基类类名naccess为继承访问控制符,规定了派生类对基类的继承方式,可为public,private或者protected,继承访问控制符可省略,此时认为为private例:classBASE{……};classA:publicBASE{ …… //单继承};classB:privateBASE,publicD{…… //多重继承};classC:publicA,B{……};BASEABDBASEC私有派生2.保护访问控制属性:protected在protected后定义的是保护段,其中的数据成员或成员函数称为受保护成员:具有公有成员与私有成员的双重角色。一个类的受保护成员,对于其子孙类(派生类)的成员函数来说是公有的,对类本身及后代类之外定义的其他函数则是私有成员。

例:classBASE{private:intx;protected:inti,j;};classD:publicBASE{ voidmake();

};

voidD::make() {intk=i*j;……}成员访问控制类自身派生类其他类public可访问可访问可访问protected可访问可访问不可访问private可访问不可访问不可访问3.继承成员函数的重定义派生类可以重新定义基类的成员函数,覆盖基类的同名函数例:classDATE{public: DATE(intyy=0,intmm=0,intdd=0);//构造函数

voidset_date(intyy,intmm,intdd);//设置日期

voidget_date(int&yy,int&mm,int&dd);//取日期

voidprint_date();

//以ANSI格式(yy.mm.dd)打印日期protected: intyear,month,day; //年、月、日};classEUROPE_DATE:publicDATE{public:

voidprint_date();

//以欧洲格式(dd-mm-yy)打印日期

voidprint(intisANSI);};

4.通过类名限定符在派生类中使用基类的同名成员voidDATE::print_date(){ //以ANSI格式(yy.mm.dd)打印日期

cout<<year<<“.”<<month<<“.”<<day<<“\n”;}voidEUROPE_DATE::print_date(){ //以欧洲格式(dd-mm-yy)打印日期

cout<<day<<“-”<<month<<“-”<<year<<“\n”;}voidEUROPE_DATE::print(int

isANSI){ if(isANSI) DATE::print_date(); else print_date();}voidmain(){ EUROPE_DATEtest; test.print_date(); //调用EUROPE_DATE中重定义的同名函数

//以欧洲格式(dd-mm-yy)打印

test.DATE::print_date(); //以ANSI格式(yy.mm.dd)打印}二、继承访问控制规则公有继承(公有派生)、私有继承、保护继承无论采用什么派生的方式,派生类中都不能访问基类的私有成员继承访问控制基类成员访问控制在派生类中的访问控制publicpublicpublicprotectedprotectedprivate不可访问protectedpublicprotectedprotectedprotectedprivate不可访问privatepublicprivateprotectedprivateprivate不可访问例:classBASE{ protected: inti,j; public: voidget_ij(); private: intx_temp;};classY1:publicBASE{ 公有派生:在Y1类中,i、j是受保护成员

floatyMember; get_ij()是公有成员};classY2:protectedBASE{保护派生:在Y2类中,i、j是受保护成员…… get_ij()变成受保护成员};classY3:privateBASE{ 私有派生:在Y3类中,i、j、get_ij()都变…… 成私有成员};三、派生类对象的存储组织派生类的对象不仅存放了在派生类中定义的非静态数据成员,而且也存放了从基类中继承下来的非静态数据成员。

例:BASEobj1;Y1obj2; obj1iJx_temp函数指针obj2iJx_tempyMember函数指针四、类型兼容性

1.赋值运算的类型兼容性类型的赋值兼容性规则允许将后代类的对象赋值给祖先类,但反之不成立。例:BASEobj1; Y1obj2; obj1=obj2;

把obj2中基类部分的内容赋给obj1 obj2=obj1;但此规则只适用于公有派生,只有公有派生类才能兼容基类类型2.参数传递与对象初始化的类型兼容性指向基类对象的指针也可指向公有派生类对象BASE*p; Y1*p1;p=&obj1; p1=&obj1;p=&obj2; p1=&obj2; p=p1;与赋值运算类型兼容性相同§7.2继承与构造函数、析构函数

一、构造函数与析构函数的调用次序

1.构造函数的调用次序在创建一个派生类的对象时先调用其基类的构造函数再调用本类对象成员的构造函数最后才调用本类的构造函数2.析构函数的调用次序先调用本类的析构函数再调用本类对象成员的析构函数最后才调用其基类的析构函数例:

#include<iostream.h>

classC{public: C()//构造函数 { cout<<"ConstructingCobject.\n"; }

~C()//析构函数 { cout<<"DestructingCobject.\n"; }};classBASE{public: BASE()//构造函数 { cout<<"Constructingbaseobject.\n"; }

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

classDERIVED:publicBASE{ C mOBJ;public: DERIVED()//构造函数 { cout<<"Constructingderivedobject.\n";}

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

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

//什么也不做,仅完成对象obj的构造与析构

return0;}运行结果:Constructingbaseobject.ConstructingCobject.Constructingderivedobject.Destructing

derivedobject.Destructing

Cobject.Destructing

baseobject.二、向基类构造函数传递实际参数给基类构造函数传递实际参数是通过向派生类构造函数传递实际参数以及初始化列表来间接实现传递的。

带初始化列表的派生类构造函数的一般形式派生类名(参数表):基类名(调用基类构造函数参数表){ 派生类构造函数体}

例:#include<iostream.h>classBase{

intprivate1,private2; public:

Base(intp1,intp2) {private1=p1;private2=p2;}

intinc1(){return++private1;} intinc2(){return++private2;}

voiddisplay(){cout<<"private1="<<private1 <<",privte2="<<private2<<"\n";}};classDerived:privateBase{ intprivate3; Baseprivate4; public:

Derived(intp1,intp2,intp3,intp4,intp5):Base(p1,p2),private4(p3,p4)

{private3=p5;}

intinc1(){returnBase::inc1();} intinc3(){return++private3;}

voiddisplay(){ Base::display(); private4.display(); cout<<"private3="<<private3<<"\n"; }};voidmain(){ Derivedobj(17,18,1,2,-5); obj.inc1(); obj.display();}输出结果:private1=18,private2=18private1=1,private2=2private3=-5obj1718-1512private1

从基类继承private2private3private4.private1private4.private218§7.3多重继承

一、多重继承多重继承:一个类由多个基类派生而来

单继承:一个类由单个基类派生而来多重继承的语法:class派生类名:access基类名1,……,

access基类名n{ …};

基类名2基类名1基类名n派生类名……二、多重继承的名字冲突问题名字冲突:指两个基类具有相同名字的成员时,在派生类中这个名字会产生二义性,即编译程序无法确定派生类的对象使用该名字时应调用哪一基类中的版本。

例:classBASE1{public: voidshow(){cout<<i<<"\n";}protected: inti;};

classBASE2{public: voidshow(){ cout<<j<<"\n";}protected: intj;};//多重继承引起名字冲突:DERIVED的两个基类BASE1和BASE2有相同的名字show()。classDERIVED:publicBASE1,publicBASE2{ public: voidset(intx,inty) {i=x; j=y; }}; //派生类在编译时不出错:C++并不禁止名字冲突的产生

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

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

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

obj.BASE1::show(); //显式地调用从BASE1继承下来show() obj.BASE2::show(); //显式地调用从BASE2继承下来show() return0;}名字冲突的解决方法使用时,用作用域运算符明确指明使用那个基类的成员函数

obj.BASE1::show();在派生类中重定义有名字冲突的成员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;}三、多重继承的构造函数和析构函数多个基类构造函数的调用次序是按基类在被继承时所声明的次序、从左到右依次调用的,与它们在派生类构造函数实现中的初始化列表中出现的次序无关。例:classDERIVED:publicBASE2,publicBASE1{ public: DERIVED(intx,inty):BASE1(x),BASE2(y) { cout<<"Constructingderivedobject.\n"; }

……};……DERIVEDobj(3,4);则obj在创建时,先调用BASE2的构造函数,然后调用BASE1的构造函数,最后才执行自己DERIVED的构造函数§7.4重复继承

一、重复继承1.定义定义:指一个派生类多次继承同一个基类C++中关于继承的限制不允许直接或间接让一个类继承自己不允许一个派生类直接继承同一个基类两次以上不允许一个基类即是直接基类又是间接基类BBACD2.重复继承的两种类型复制继承:被多次重复继承的基类有多个实体副本

共享继承:被多次重复继承的基类只有一个实体副本

例:BBACDBACD二、重复继承的二义性问题若在继承时没有作特殊声明,此时采用的是复制继承,会导致重复继承的二义性问题。例:classBASE{public: inti;};

classBASE1:publicBASE{ public: intj;};

classBASE2:publicBASE{ public: intk;};

classDERIVED:publicBASE1,publicBASE2{ public: intsum;};

voidmain(){ DERIVEDobj; //声明一个派生类对象

//obj.i=3; //错误,编译程序无法确定使用i的哪一份副本

obj.j=5; //正确的,使用从BASE1继承下来的j obj.k=7; //正确的,使用从BASE2继承下来的k}BASEBASEBASE1BASE2DERIVEDobj

BASE1.BASE.iBASE1.jBASE2.BASE.iBASE2.ksum

函数指针解决二义性的方法如不改变重复继承的方法(还是复制继承),则采用作用域运算符::明确指明采用哪个副本

intmain() { DERIVEDobj;

温馨提示

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

评论

0/150

提交评论