第十七章多重继承_第1页
第十七章多重继承_第2页
第十七章多重继承_第3页
第十七章多重继承_第4页
第十七章多重继承_第5页
已阅读5页,还剩78页未读 继续免费阅读

下载本文档

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

文档简介

第十七章多重继承第一页,共八十三页,编辑于2023年,星期五2本章主要内容多继承如何工作多继承的构造顺序继承的模糊性(二义性问题)虚基类保护继承与私有继承第二页,共八十三页,编辑于2023年,星期五3在现实世界中存在一个类是由多个类派生的情况。两用沙发,它是一个沙发,也是一个床。两用沙发应允许同时继承沙发和床的特征。第三页,共八十三页,编辑于2023年,星期五4多继承时派生类的定义class派生类名:继承方式1基类名1,

继承方式2基类名2,...{

成员定义;}注意:每一个“继承方式”,只用于限制对紧随其后之基类的继承。第四页,共八十三页,编辑于2023年,星期五5,所讨论的类层次中,每个类只继承一个父辈,在现实世界中事情通常是这样的。但是一些类却代表两个类的合成。例如,两用沙发,它是一个沙发,也是一张床,两用沙发应允许同时继承沙发和床的特征,即SleeperSofa继承Bed和Sofa两个类,如图所示。其程序代码如下:两用沙发的类层次第五页,共八十三页,编辑于2023年,星期五6classBed{public: Bed():weight(0){} voidSleep(){cout<<"Sleeping...\n";} voidSetWeight(inti){weight=i;}protected: intweight;};classSofa{public: Sofa():weight(0){} voidWatchTV(){cout<<"WatchingTV.\n";} voidSetWeight(inti){weight=i;}protected: intweight;};第六页,共八十三页,编辑于2023年,星期五7classSleeperSofa:publicBed,publicSofa{public: SleeperSofa(){} voidFoldOut(){cout<<"Foldoutthesofa.\n";}};voidmain(){ SleeperSofass; ss.WatchTV(); ss.FoldOut(); ss.Sleep(); cin.get();}

第七页,共八十三页,编辑于2023年,星期五8运行结果为:

WatchingTV.

Foldoutthesofa.

Sleeping...两用沙发继承两个基类的所有成员,这样ss.Sleep()和ss.WmchTV()的调用是合法的。也就可以把SleeperSofa)fa当作一个Bed或一个Sofa用。另外,SleeperSoa类还有它自己的成员FoldOut()。第八页,共八十三页,编辑于2023年,星期五9多继承举例classA{public:voidsetA(int);voidshowA();private:inta;};classB{public:voidsetB(int);voidshowB();private:intb;};classC:publicA,privateB{public:voidsetC(int,int,int);voidshowC();private:intc;};第九页,共八十三页,编辑于2023年,星期五voidA::setA(intx){a=x;}voidB::setB(intx){b=x;}voidC::setC(intx,inty,intz){SetA(x);SetB(y);c=z;}//其它函数实现略intmain(){Cobj;obj.setA(5);obj.showA();obj.setC(6,7,9);obj.showC();obj.setB(6);obj.showB();return0;}//error//error第十页,共八十三页,编辑于2023年,星期五11本章主要内容多继承如何工作继承的模糊性(二义性问题)多继承的构造顺序虚基类第十一页,共八十三页,编辑于2023年,星期五12Sofa和Bed都有一个成员weight,这是合理的,因为两者都是实体,都有一个重量。问题是SleeperSofa继承哪个重量?既然两者都继承,由于两者有相同的名字weight,使得对weight的引用变得模糊不清。第十二页,共八十三页,编辑于2023年,星期五13二义性问题在多继承时,基类之间出现同名成员时,将出现访问时的二义性(不确定性)。例如,按照下面引用:

voidmain() { SleeperSofass;

ss.SetWeight(20);

//Bed的SetWeight还是Sofa的SetWeight? }第十三页,共八十三页,编辑于2023年,星期五14这样导致了名称冲突(namecollision),在编译时将予以拒绝。程序必须在重量前面说明基类:voidmain(){SleeperSofass;

ss.Sofa::SetWeight(20);//说明是沙发重量20斤}

在编写应用程序时,程序员还得额外知道类的层次信息,加大了复杂度。这些在单继承中是不会出现的。第十四页,共八十三页,编辑于2023年,星期五15二义性问题举例classA{public:voidf();};classB{public:voidf();voidg();};classC:publicA,publicB{public:voidg();voidh();};main(){Cc;c.f();c.g();}//error第十五页,共八十三页,编辑于2023年,星期五16二义性的解决方法解决方法一:用类名来限定

c1.A::f()或c1.B::f()解决方法二:同名覆盖

在C中定义一个同名成员函数f(),f()再根据需要调用A::f()或B::f()第十六页,共八十三页,编辑于2023年,星期五17二义性问题的说明二义性检查是在访问控制或类型检查之前进行的。因此当不同基类成员中具有相同名字时就会出现二义性,即只有一个名字是可以被派生类访问或只有一个名字的类型与要求相符。第十七页,共八十三页,编辑于2023年,星期五18本章主要内容多继承如何工作继承的模糊性(二义性问题)虚基类多继承的构造顺序第十八页,共八十三页,编辑于2023年,星期五19为什么要引入虚基类?在C++中,一个类不能多次说明为派生类的直接基类,但一个类可以不止一次的成为某个类的间接基类。第十九页,共八十三页,编辑于2023年,星期五20从意义上来看,一个SleeperSofa没有沙发和床两种重量,如此的继承不是真实的现实世界描述。进一步分析可得,床和沙发都是家具的一种,凡家具都有重量,所以通过分解来考察其关系,如图

第二十页,共八十三页,编辑于2023年,星期五21classFurniture{public: Furniture(){}

voidSetWeight(inti){weight=i;} intGetWeight(){returnweight;}protected: intweight;};classBed:publicFurniture{public: Bed(){} voidSleep(){cout<<"Sleeping...\n";}};classSofa:publicFurniture{public: Sofa(){} voidWatchTV(){cout<<"WatchingTV.\n";}};第二十一页,共八十三页,编辑于2023年,星期五22classSleeperSofa:publicBed,publicSofa{public: SleeperSofa():Sofa(),Bed(){} voidFoldOut(){cout<<"Foldoutthesofa.\n";}};voidmain(){ SleeperSofass; ss.SetWeight(20);//编译出错!模糊的SetWeight成员

Furniture*pF; pF=(Furniture*)&ss;//编译出错!模糊的Furniture* cout<<pF->GetWeight()<<endl;}第二十二页,共八十三页,编辑于2023年,星期五23因为SlleperSofa不是直接继承Furniture,而是Bed和Sofa各自继承Furniture,所以完整的SleeperSofa对象内存布局如图所示完整SleeperSofa对象内存布局第二十三页,共八十三页,编辑于2023年,星期五24这里一个Sleepersofa包括一个完整的Bed,随后还有一个完整的Sofa,后面还有一个Sleepersofa特有的东西。SleeperSofa中的每一个子对象都有它自己的Furniture部分。因为每个子对象继承Furniture,所以一个SleeperSofa包含两个Furniture对象,编译源文件时,不知道SetWeight()属于哪一个Furniture成员,指向Furniture的指针也不知道究竟指哪一个Furniture。这就是为什么源文件编译通不过的原因。

SleeperSofa只需一个Fumiture,所以我们希望它只含一个Furniture拷贝,同时又要共享Bed和Sofa的成员函数与数据成员,C++实现这种继承结构的方法称为虚拟继承(virtualinheritance)。第二十四页,共八十三页,编辑于2023年,星期五25虚基类的概念当在多条继承路径上有一个公共的基类,在这些路径中的某几条的交汇处,这个公共的基类就会产生多个副本。在大多数的应用场合,需要派生类对象中所含基类的副本只有一个,而不是多个。C++中的虚基类机制可以实现这种要求。第二十五页,共八十三页,编辑于2023年,星期五26定义用virtual修饰说明基类

例:classx1:

virtualpublicx{//…}classx2:virtualpublicx{//…}注意:在第一级继承时就要将共同基类设计为虚基类。第二十六页,共八十三页,编辑于2023年,星期五27虚基类举例classB{public:intb;};classB1:virtualpublicB{private:intb1;};classB2:virtualpublicB{private:intb2;};classC:publicB1,publicB2{private:floatd;};下面的访问是正确的:

Cobj;obj.b;第二十七页,共八十三页,编辑于2023年,星期五28虚基类的派生类对象存储结构示意图:BB1B2Cb1b2dB1类子对象B2类子对象C类对象bB类子对象第二十八页,共八十三页,编辑于2023年,星期五29下面是虚拟继承的代码:classFurniture{public: Furniture(){} voidSetWeight(inti){weight=i;} intGetWeight(){returnweight;}protected: intweight;};classBed:virtualpublicFurniture{public: Bed(){} voidSleep(){cout<<"Sleeping...\n";}};classSofa:virtualpublicFurniture{public: Sofa(){} voidWatchTV(){cout<<"WatchingTV.\n";}};第二十九页,共八十三页,编辑于2023年,星期五30classSleeperSofa:publicBed,publicSofa{public: SleeperSofa():Sofa(),Bed(){} voidFoldOut(){cout<<"Foldoutthesofa.\n";}};voidmain(){ SleeperSofass; ss.SetWeight(20); cout<<ss.GetWeight()<<endl;}运行结果为:

20第三十页,共八十三页,编辑于2023年,星期五31

在Bed和Sofa继承Furniture中加上virtual关键字,这相当于说,“如果还没有Furniture类,则加入一个Furniture拷贝,否则就用有的那一个”。此时一个Sleepersofa在内存中的布局见图

在虚拟继承的情况下,应用程序main()中引用GetWeight()不再模糊,我们得到了真正的图17-2所示的继承关系。->虚拟继承的虚拟和虚拟函数的虚拟没有任何关系。第三十一页,共八十三页,编辑于2023年,星期五32虚基类及其派生类构造函数在整个继承结构中,直接或间接继承虚基类的所有派生类,都必须在构造函数的成员初始化表中给出对虚基类的构造函数的调用。如果未列出,则表示调用该虚基类的默认构造函数。在建立对象时,只有最新派生类的构造函数调用虚基类的构造函数,该派生类的其它基类对虚基类构造函数的调用被忽略。虚基类的构造函数先于非虚基类的构造函数执行。第三十二页,共八十三页,编辑于2023年,星期五33应用举例人员管理系统:有三类人员:经理、技术人员、推销人员,还有销售经理。月薪:经理:8000元/月;技术人员:100元/小时;推销人员:4%提成;销售经理:5000元月+5%提成。输出每个人员的月工资信息。第三十三页,共八十三页,编辑于2023年,星期五34应用举例类设计基类:employee派生类:technician、manager和salesman多继承派生类:salesmanager第三十四页,共八十三页,编辑于2023年,星期五35classemployee{protected:

char*name; //姓名

intindividualEmpNo; //个人编号

floataccumPay; //月薪总额

staticintemployeeNo; //本公司职员 编号目前最大值

public:

employee(); //构造函数

~employee(); //析构函数

virtualvoidpay()=0; //计算月薪函数

virtualvoiddisplayStatus()=0;//显示人员信息

};第三十五页,共八十三页,编辑于2023年,星期五36

classtechnician:publicemployee//技术人员类

{private:

floathourlyRate; //每小时酬金

intworkHours; //当月工作时数

public:

technician(); //构造函数

voidpay(); //计算月薪函数

voiddisplayStatus();//显示人员信息};第三十六页,共八十三页,编辑于2023年,星期五37classsalesman:virtualpublicemployee//兼职推销员类{protected:

floatCommRate;//按销售额提取酬金的百分比

floatsales; //当月销售额

public:

salesman(); //构造函数

voidpay(); //计算月薪函数

voiddisplayStatus();//显示人员信息};第三十七页,共八十三页,编辑于2023年,星期五38classmanager:virtualpublicemployee//经理类{protected:floatmonthlyPay; //固定月薪数

public:manager(); //构造函数

voidpay(); //计算月薪函数

voiddisplayStatus();//显示人员信息

};第三十八页,共八十三页,编辑于2023年,星期五39classsalesmanager:publicmanager,publicsalesman//销售经理类

{public:salesmanager();//构造函数

voidpay();//计算月薪函数

voiddisplayStatus();//显示人员信息

};第三十九页,共八十三页,编辑于2023年,星期五40employee::employee(){charnamestr[50]; //输人雇员姓名时首先临时存放在namestr中

cout<<"请输入下一个雇员的姓名:"; cin>>namestr;name=newchar[strlen(namestr)+1]; //动态申请用于存放姓名的内存空间

strcpy(name,namestr);//将临时存放的姓名复制到nameindividualEmpNo=employeeNo++;//新输人的员工,其编号为目前最大编号加1 accumPay=0.0;//月薪总额初值为0}第四十页,共八十三页,编辑于2023年,星期五41employee::~employee(){deletename; //在析构函数中删除为存放姓名动态分配的内存空间}第四十一页,共八十三页,编辑于2023年,星期五42technician::technician(){hourlyRate=100;//每小时酬金100元}voidtechnician::pay(){cout<<"请输入"<<name<<"本月的工作时数:";cin>>workHours;accumPay=hourlyRate*workHours; //计算月薪,按小时计酬

cout<<“兼职技术人员”<<name<<“编号“

<<individualEmpNo<<“本月工资”

<<accumPay<<endl;}voidtechnician::displayStatus(){cout<<“兼职技术人员”<<name<<“编号”

<<individualEmpNo<<"级别为"<<grade<<"级,已付本月工资"<<accumPay<<endl;}第四十二页,共八十三页,编辑于2023年,星期五43salesman::salesman(){CommRate=0.04;//销售提成比例4%}voidsalesman::pay(){cout<<"请输入"<<name<<"本月的销售额:";cin>>sales;accumPay=sales*CommRate;//月薪=销售提成

cout<<"推销员"<<name<<"编号"<<individualEmpNo<<"本月工资"<<accumPay<<endl;}voidsalesman::displayStatus(){cout<<"推销员"<<name<<"编号"<<individualEmpNo<<“级别为”<<grade<<“级,已付本月工资”

<<accumPay<<endl;}第四十三页,共八十三页,编辑于2023年,星期五44manager::manager(){monthlyPay=8000;//固定月薪8000元}voidmanager::pay(){accumPay=monthlyPay;//月薪总额即固定月薪数

cout<<"经理"<<name<<"编号"<<individualEmpNo<<"本月工资"<<accumPay<<endl;}voidmanager::displayStatus(){cout<<"经理"<<name<<"编号"<<individualEmpNo<<“级别为”<<grade<<“级,已付本月工资”

<<accumPay<<endl;}第四十四页,共八十三页,编辑于2023年,星期五45salesmanager::salesmanager(){monthlyPay=5000;CommRate=0.005;}voidsalesmanager::pay(){cout<<“请输入”<<employee::name<<“所管辖部门本月的销售总额:";cin>>sales;accumPay=monthlyPay+CommRate*sales;//月薪=固定月薪十销售提成

cout<<"销售经理"<<name<<"编号"<<individualEmpNo<<"本月工资"<<accumPay<<endl;}voidsalesmanager::displayStatus(){cout<<"销售经理"<<name<<"编号"<<individualEmpNo<<“级别为”<<grade<<“级,已付本月工资”

<<accumPay<<endl;}第四十五页,共八十三页,编辑于2023年,星期五46intmain(){managerm1;techniciant1;salesmanagersm1;salesmans1;employee*emp[4]={&m1,&t1,&sm1,&s1}; //用指针数组存放各个对象的地址

for(inti=0;i<4;i++){emp[i]->pay(); //显示月薪

emp[i]->displayStatus(); //显示人员信息

}return0;}第四十六页,共八十三页,编辑于2023年,星期五47本章主要内容多继承如何工作继承的模糊性(二义性问题)虚基类多继承的构造顺序保护继承与私有继承第四十七页,共八十三页,编辑于2023年,星期五48多继承时的构造函数派生类名::派生类名(基类1形参,基类2形参,…,基类n形参,本类形参):基类名1(参数),基类名2(参数),…,基类名n(参数){

本类成员初始化赋值语句;};第四十八页,共八十三页,编辑于2023年,星期五49多继承时的构造函数当基类中定义有默认形式的构造函数或未定义构造函数时,派生类构造函数的定义中可以省略对基类构造函数的调用,也可以不定义,全采用默认形式构造函数。当基类定义有带形参的构造函数时,派生类也应定义构造函数,提供将参数传递给基类构造函数的途径。第四十九页,共八十三页,编辑于2023年,星期五50构造函数的调用次序1.调用基类构造函数,调用顺序按照它们被继承时声明的顺序(从左向右)。2.调用成员对象的构造函数,调用顺序按照它们在类中声明的顺序。3.派生类的构造函数体中的内容。第五十页,共八十三页,编辑于2023年,星期五51多继承且有内嵌对象时

的构造函数派生类名::派生类名(基类1形参,基类2形参,…,基类n形参,本类形参):基类名1(参数),基类名2(参数),...基类名n(参数),对象数据成员的初始化{

本类成员初始化赋值语句;};第五十一页,共八十三页,编辑于2023年,星期五52举例#include<iostream.h>classB1{public:B1(inti){cout<<“ConstructingB1”<<i<<endl;}};classB2{public:B2(intj){cout<<“ConstructingB2”<<j<<endl;}};第五十二页,共八十三页,编辑于2023年,星期五classB3{public:B3(){cout<<“ConstructingB3*”<<endl;}};classC:publicB2,publicB1,publicB3//派生类{public:C(inta,intb,intc,intd): B1(a),memB2(d),memB1(c),B2(b){}private:B1memB1;

B2memB2; B3memB3;};voidmain(){Cobj(1,2,3,4);}第五十三页,共八十三页,编辑于2023年,星期五调用顺序:先按派生类声明时基类的顺序调用基类的构造函数:B2、B1、B3;再按成员对象定义的顺序,调用成员对象的构造函数:B1、B2、B3程序运行结果:ConstructingB22ConstructingB11ConstructingB3*ConstructingB13ConstructingB24ConstructingB3*第五十四页,共八十三页,编辑于2023年,星期五55多重继承带有虚拟基类的顺序构造对象的规则需要扩展以控制多重继承。构造函数按下列顺序被调用:

(1)任何虚拟基类的构造函数按照它们被继承的顺序构造;

(2)任何非虚拟基类的构造函数按照它们被继承的顺序构造;

(3)任何成员对象的构造函数按照它们声明的顺序调用;

(4)类自己的构造函数。第五十五页,共八十三页,编辑于2023年,星期五56classOBJ1{public: OBJ1(){cout<<"OBJ1\n";}};classOBJ2{public: OBJ2(){cout<<"OBJ2\n";}};第五十六页,共八十三页,编辑于2023年,星期五57classBase1{public: Base1(){cout<<"Base1\n";}};classBase2{public: Base2(){cout<<"Base2\n";}};classBase3{public: Base3(){cout<<"Base3\n";}};classBase4{public: Base4(){cout<<"Base4\n";}};第五十七页,共八十三页,编辑于2023年,星期五58classDerived:publicBase1,virtualpublicBase2,publicBase3,virtualpublicBase4{public: Derived():Base4(),Base3(),Base2(),Base1(),obj2(),obj1() { cout<<"Derivedok.\n"; }protected: OBJ1obj1; OBJ2obj2;};voidmain(){ Derivedaa; cout<<"Thisisok.\n";}第五十八页,共八十三页,编辑于2023年,星期五59运行结果为:

Base2 Base4 Base1 Base3 OBJ1 OBJ2 Derivedok. Thisisok.

Derived的虚基类Base2和Base4最先构造,尽管它在Derived类中出现的顺序不在最前面;Derived的非虚基类其次构造,不管它在Derived构造函数中出现的顺序如何;Derived的组合对象obj1和。obj2随后构造,它以类定义时,数据成员排列顺序为准,不管在Derived构造函数中出现顺序怎样;最后是Derived类构造函数本身。第五十九页,共八十三页,编辑于2023年,星期五60>在语言中实现多继承并不容易,这主要是编译程序问题,还有模糊性问题。建议你如果可能,在进一步阅读有关参考书之前,尽量避免用多重继承。单个继承提供了足够强大的功能,不一定非用多重继承不可。我们应先学会阅读一些商品化的类库源程序中有关多重继承的部分,因为那些都是经过测试的安全代码。第六十页,共八十三页,编辑于2023年,星期五61本章主要内容多继承如何工作多继承的构造顺序继承的模糊性(二义性问题)虚基类继承的访问控制

保护继承与私有继承

第六十一页,共八十三页,编辑于2023年,星期五62

继承可以公共继承,也可保护继承和私有继承。对于不同的继承方式,其访问控制是不同的第六十二页,共八十三页,编辑于2023年,星期五63我们在前面讨论的类的继承关系都是公共继承的。在公共继承的类中,基类的每个成员在子类中保持同样的访问方式。即在基类中为public的成员,子类中可以访问之,并据为public的;基类中为protected的成员,子类中也可访问之,并据为protected的;基类中为private的成员,在子类中不能访问之,这就像在应用程序中不能访问类中私有成员一样。下面的例子中的代码,是对上表的一个解释:第六十三页,共八十三页,编辑于2023年,星期五64classBase {public: intm1;protected: intm2;private: intm3; };classPrivateClass:privateBase//私有继承

{ public: voidtest() { m1=1;//ok:将m1据为private m2=2;//ok:将m2据为private m3=3;//不可访问

} };第六十四页,共八十三页,编辑于2023年,星期五65classDerivedFromPri:publicPrivateClass { public: voidtest() { m1=1;//不可访问基类的私有成员

m2=2;//不可访问

m3=3;///不可访问

} };classProtectedClass:protectedBase//保护继承

{ public: voidtest() { m1=1;//ml据为protected m2=2;//m2据为protected m3=3;//不可访问

} };第六十五页,共八十三页,编辑于2023年,星期五66classDerivedFromPro:publicProtectedClass { public: voidtest() { m1=1;//ml仍为protected m2=2;//m2仍为protected m3=3;//不可访问

} };classPublicClass:publicBase//公共继承

{ public: voidtest() { m1=1;//ml为public m2=2;//m2为protected m3=3;//不可访问

} };第六十六页,共八十三页,编辑于2023年,星期五67classDerivedFromPub:publicPublicClass { public: voidtest() { m1=1;//ml仍保持为public m2=2;//m2仍保持为prOtected m3=3;//不可访问

}

}; 第六十七页,共八十三页,编辑于2023年,星期五68 voidmain() {

PrivateClasspriObj; priObj.m1=1;//error priObj.m2=2;//error priObj.m3=3;//error ProtectedClassproObj; proObj.m1=1;//error proObj.m2=2;//error proObj.m3=3;//error PublicClasspubObj; pubObj.m1=1; pubObj.m2=2;//error pubObj.m3=3;//error

}第六十八页,共八十三页,编辑于2023年,星期五69类Base包括三个成员m1,m2,m3,分别定义为public,protected,private。Base作为PrivateClass,ProtectedClass,PublicClass三个类的基类,这三个类分别用私有、保护和公共继承派生。于是在这三个类中,数据成员的性质发生了变化:私有继承时,基类中不管是公有的,还是保护的或者为私有的,一律在子类中变成私有成员。保护继承时,基类中公共和保护的成员在子类中变成保护的,而基类中私有的成员在子类中变成私有的。公共继承时,基类中为公共、保护和私有的成员在子类中仍保持为公共、保护和私有的。第六十九页,共八十三页,编辑于2023年,星期五70m3是私有的,它只能被Base访问,不能被派生类和非成员函数访问。在所有的test()函数中引用m3时将报错。m1和m2对直接从Base派生的类都可以访问。所以由PrivateClass::test(),ProtectedClass::test()和PublicClass::test()引用这两个成员是允许的。

PrivateClass类私有继承Base,这意味着m1和m2对PrivateClass中的成员现在可以私有访问。因而不能被像DerivedFromPri一样由PrivateClass直接派生的类访问。

ProtectedClass类被保护地继承Base,这使得m1和m2都被保护。对ProtectedClass::test()和DerivedFromPro::test()这两个成员都是可访问的。第七十页,共八十三页,编辑于2023年,星期五71PublicClass类公共继承Base。在PublicClass中三个成员都保持它们在Base中的访问特性。如果不标明继承为公共还是保护或者私有,则默认的继承是私有。但最好不要依赖默认,如果把继承类型表示清楚,则程序的可读性会更好。在单个类中,protected和private没有什么区别。但在继承关系中,基类的private成员不但对应用程序隐藏,甚至对派生类也隐藏。而基类的保护成员则只对应用程序隐藏,而对派生类则毫不隐瞒。第七十一页,共八十三页,编辑于2023年,星期五72本章主要内容多继承如何工作多继承的构造顺序继承的模糊性(二义性问题)虚基类继承的访问控制

保护继承与私有继承

第七十二页,共八十三页,编辑于2023年,星期五73

一个私有的或保护的派生类不是子类,因为非公共的派生类不能做基类能做的所有的事。例如,下面的代码定义了一个私有继承基类的类第七十三页,共八十三页,编辑于2023年,星期五74classAnimal { public:

Animal(){}voideat(){cout<<"eat\n";} };

classGiraffe:privateAnimal { public;

Giraffe(){} voidStrechNeck(double){cout<<"strechneck\n";} } classCat:publicAnimal { Ca

温馨提示

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

评论

0/150

提交评论