《第十七章多重继承精选文档.ppt》由会员分享,可在线阅读,更多相关《第十七章多重继承精选文档.ppt(83页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、第十七章多重继承本讲稿第一页,共八十三页2本章主要内容多继承如何工作多继承的构造顺序继承的模糊性(二义性问题)虚基类保护继承与私有继承保护继承与私有继承本讲稿第二页,共八十三页3在现实世界中存在一个类是由多个类派生的情况。两用沙发,它是一个沙发,也是一个床。两用沙发应允许同时继承沙发和床的特征。本讲稿第三页,共八十三页4多继承时派生类的定义class 派生类名:继承方式1 基类名1,继承方式2 基类名2,.成员定义;注意注意:每一个:每一个“继承方式继承方式”,只用于限制,只用于限制对紧随其后之基类的继承。对紧随其后之基类的继承。本讲稿第四页,共八十三页5,所讨论的类层次中,每个类只继承一个父
2、辈,在现实世界中事情通常是这样的。但是一些类却代表两个类的合成。例如,两用沙发,它是一个沙发,也是一张床,两用沙发应允许同时继承沙发和床的特征,即SleeperSofa继承Bed和Sofa两个类,如图所示。其程序代码如下:两用沙发的类层次 本讲稿第五页,共八十三页6class Bedpublic:Bed():weight(0)void Sleep()cout Sleeping.n;void SetWeight(int i)weight=i;protected:int weight;class Sofapublic:Sofa():weight(0)void WatchTV()cout Watch
3、ing TV.n;void SetWeight(int i)weight=i;protected:int weight;本讲稿第六页,共八十三页7class SleeperSofa:public Bed,public Sofapublic:SleeperSofa()void FoldOut()cout Fold out the sofa.n;void main()SleeperSofa ss;ss.WatchTV();ss.FoldOut();ss.Sleep();cin.get();本讲稿第七页,共八十三页8运行结果为:Watching TV Fold out the sofa Sleepi
4、ng两用沙发继承两个基类的所有成员,这样ssSleep()和ssWmchTV()的调用是合法的。也就可以把SleeperSofa)fa当作一个Bed或一个Sofa用。另外,SleeperSoa类还有它自己的成员FoldOut()。本讲稿第八页,共八十三页9多继承举例class A public:void setA(int);void showA();private:int a;class B public:void setB(int);void showB();private:int b;class C:public A,private B public:void setC(int,int,i
5、nt);void showC();private:int c;本讲稿第九页,共八十三页void A:setA(int x)a=x;void B:setB(int x)b=x;void C:setC(int x,int y,int z)SetA(x);SetB(y);c=z;/其它函数实现略int main()C obj;obj.setA(5);obj.showA();obj.setC(6,7,9);obj.showC();obj.setB(6);obj.showB();return 0;/error/error本讲稿第十页,共八十三页11本章主要内容本章主要内容多继承如何工作多继承如何工作继承
6、的模糊性(二义性问题)继承的模糊性(二义性问题)多继承的构造顺序多继承的构造顺序虚基类虚基类本讲稿第十一页,共八十三页12Sofa和Bed都有一个成员weight,这是合理的,因为两者都是实体,都有一个重量。问题是SleeperSofa继承哪个重量?既然两者都继承,由于两者有相同的名字weight,使得对weight的引用变得模糊不清。本讲稿第十二页,共八十三页13二义性问题在多继承时,基类之间出现同名成员时,将出现访问时的二义性(不确定性)。例如,按照下面引用:例如,按照下面引用:void main()SleeperSofa ss;ss.SetWeight(20);/Bed的的SetWeig
7、ht还是还是Sofa的的SetWeight?本讲稿第十三页,共八十三页14这样导致了名称冲突(name collision),在编译时将予以拒绝。程序必须在重量前面说明基类:void main()SleeperSofa ss;ss.Sofa:SetWeight(20);/说明是沙发重量20斤 在编写应用程序时,程序员还得额外知道类的层次信息,加大了复杂度。这些在单继承中是不会出现的。本讲稿第十四页,共八十三页15二义性问题举例class A public:void f();class B public:void f();void g();class C:public A,public B pu
8、blic:void g();void h();main()C c;c.f();c.g();/error本讲稿第十五页,共八十三页16二义性的解决方法解决方法一:用类名来限定c1.A:f()或 c1.B:f()解决方法二:同名覆盖在C 中定义一个同名成员函数f(),f()再根据需要调用 A:f()或 B:f()本讲稿第十六页,共八十三页17二义性问题的说明二义性检查是在访问控制或类型检查之前进行的。因此当不同基类成员中具有相同名字时就会出现二义性,即只有一个名字是可以被派生类访问或只有一个名字的类型与要求相符。本讲稿第十七页,共八十三页18本章主要内容本章主要内容多继承如何工作多继承如何工作继承
9、的模糊性(二义性问题)继承的模糊性(二义性问题)虚基类虚基类多继承的构造顺序多继承的构造顺序本讲稿第十八页,共八十三页19为什么要引入虚基类?在C+中,一个类不能多次说明为派生类的直接基类,但一个类可以不止一次的成为某个类的间接基类。本讲稿第十九页,共八十三页20从意义上来看,一个SleeperSofa没有沙发和床两种重量,如此的继承不是真实的现实世界描述。进一步分析可得,床和沙发都是家具的一种,凡家具都有重量,所以通过分解来考察其关系,如图 本讲稿第二十页,共八十三页21class Furniturepublic:Furniture()void SetWeight(int i)weight=
10、i;int GetWeight()return weight;protected:int weight;class Bed:public Furniturepublic:Bed()void Sleep()cout Sleeping.n;class Sofa:public Furniturepublic:Sofa()void WatchTV()cout Watching TV.n;本讲稿第二十一页,共八十三页22class SleeperSofa:public Bed,public Sofapublic:SleeperSofa():Sofa(),Bed()void FoldOut()cout F
11、old out the sofa.n;void main()SleeperSofa ss;ss.SetWeight(20);/编译出错!模糊的SetWeight成员 Furniture*pF;pF=(Furniture*)&ss;/编译出错!模糊的Furniture*cout GetWeight()endl;本讲稿第二十二页,共八十三页23因为SlleperSofa不是直接继承Furniture,而是Bed和Sofa各自继承Furniture,所以完整的SleeperSofa对象内存布局如图 所示 完整SleeperSofa对象内存布局 本讲稿第二十三页,共八十三页24这里一个Sleepers
12、ofa包括一个完整的Bed,随后还有一个完整的Sofa,后面还有一个 Sleepersofa特有的东西。SleeperSofa中的每一个子对象都有它自己的Furniture部分。因为每个子对象继承Furniture,所以一个SleeperSofa包含两个Furniture对象,编译源文件时,不知道SetWeight()属于哪一个Furniture成员,指向Furniture的指针也不知道究竟指哪一个Furniture。这就是为什么源文件编译通不过的原因。SleeperSofa只需一个Fumiture,所以我们希望它只含一个Furniture拷贝,同时又要共享Bed和Sofa的成员函数与数据成员
13、,C+实现这种继承结构的方法称为虚拟继承虚拟继承(virtual inheritance)。本讲稿第二十四页,共八十三页25虚基类的概念当在多条继承路径上有一个公共的基类,在这些路径中的某几条的交汇处,这个公共的基类就会产生多个副本。在大多数的应用场合,需要派生类对象中所含基类的副本只有一个,而不是多个。C+中的虚基类机制可以实现这种要求。本讲稿第二十五页,共八十三页26定义用 virtual 修饰说明基类 例例:class x1:virtual public x /class x2:virtual public x /注意:在第一级继承时就要将共同基类设计为在第一级继承时就要将共同基类设计为
14、虚基类。虚基类。本讲稿第二十六页,共八十三页27虚基类举例class B public:int b;class B1:virtual public B private:int b1;class B2:virtual public B private:int b2;class C:public B1,public B2 private:float d;下面的访问是正确的:下面的访问是正确的:C obj;obj.b;本讲稿第二十七页,共八十三页28虚基类的派生类对象存储结构示意图:BB1B2Cb1b2dB1类子对象B2类子对象C类对象bB类子对象本讲稿第二十八页,共八十三页29下面是虚拟继承的代码
15、:class Furniturepublic:Furniture()void SetWeight(int i)weight=i;int GetWeight()return weight;protected:int weight;class Bed:virtual public Furniturepublic:Bed()void Sleep()cout Sleeping.n;class Sofa:virtual public Furniturepublic:Sofa()void WatchTV()cout Watching TV.n;本讲稿第二十九页,共八十三页30class SleeperSo
16、fa:public Bed,public Sofapublic:SleeperSofa():Sofa(),Bed()void FoldOut()cout Fold out the sofa.n;void main()SleeperSofa ss;ss.SetWeight(20);cout ss.GetWeight()虚拟继承的虚拟和虚拟函数的虚拟没有任何关系。虚拟继承的虚拟和虚拟函数的虚拟没有任何关系。本讲稿第三十一页,共八十三页32虚基类及其派生类构造函数在整个继承结构中,直接或间接继承虚基类的所有派生类,都必须在构造函数的成员初始化表中给出对虚基类的构造函数的调用。如果未列出,则表示调用该
17、虚基类的默认构造函数。在建立对象时,只有最新派生类的构造函数调用虚基类的构造函数,该派生类的其它基类对虚基类构造函数的调用被忽略。虚基类的构造函数先于非虚基类的构造函数执行。本讲稿第三十二页,共八十三页33应用举例人员管理系统:有三类人员:经理、技术人员、推销人员,还有销售经理。月薪:经理:8000元/月;技术人员:100元/小时;推销人员:4%提成;销售经理:5000元月+5%提成。输出每个人员的月工资信息。本讲稿第三十三页,共八十三页34应用举例类设计基类:employee派生类:technician、manager和salesman多继承派生类:salesmanager本讲稿第三十四页,
18、共八十三页35class employee protected:char*name;/姓名姓名 int individualEmpNo;/个人编号个人编号 float accumPay;/月薪总额月薪总额 static int employeeNo;/本公司职员本公司职员编号目前最大值编号目前最大值 public:employee();/构造函数构造函数 employee();/析构函数析构函数 virtual void pay()=0;/计算月薪函数计算月薪函数 virtual void displayStatus()=0;/显示人员信息显示人员信息 ;本讲稿第三十五页,共八十三页36 cl
19、ass technician:public employee /技术人员类 private:float hourlyRate;/每小时酬金每小时酬金 int workHours;/当月工作时数当月工作时数 public:technician();/构造函数构造函数 void pay();/计算月薪函数计算月薪函数 void displayStatus();/显示人员信息显示人员信息;本讲稿第三十六页,共八十三页37class salesman:virtual public employee /兼职推销员类 protected:float CommRate;/按销售额提取酬金的百分比按销售额提取
20、酬金的百分比 float sales;/当月销售额当月销售额 public:salesman();/构造函数构造函数 void pay();/计算月薪函数计算月薪函数 void displayStatus();/显示人员信息显示人员信息;本讲稿第三十七页,共八十三页38class manager:virtual public employee /经理类 protected:float monthlyPay;/固定月薪数固定月薪数 public:manager();/构造函数构造函数 void pay();/计算月薪函数计算月薪函数 void displayStatus();/显示人员信息显示人
21、员信息 ;本讲稿第三十八页,共八十三页39class salesmanager:public manager,public salesman /销售经理类 public:salesmanager();/构造函数 void pay();/计算月薪函数 void displayStatus();/显示人员信息 ;本讲稿第三十九页,共八十三页40employee:employee()char namestr50;/输人雇员姓名时首先临时存放在namestr中coutnamestr;name=new charstrlen(namestr)+1;/动态申请用于存放姓名的内存空间 strcpy(name,
22、namestr);/将临时存放的姓名复制到 name individualEmpNo=employeeNo+;/新输人的员工,其编号为目前最大编号加1accumPay=0.0;/月薪总额初值为0 本讲稿第四十页,共八十三页41employee:employee()delete name;/在析构函数中删除为存放姓名动态分配的内存空间本讲稿第四十一页,共八十三页42technician:technician()hourlyRate=100;/每小时酬金100元void technician:pay()cout请输入nameworkHours;accumPay=hourlyRate*workHou
23、rs;/计算月薪,按小时计酬 cout“兼职技术人员”name“编号“individualEmpNo“本月工资”accumPayendl;void technician:displayStatus()cout“兼职技术人员”name“编号”individualEmpNo 级别为 grade 级,已付本月工资accumPayendl;本讲稿第四十二页,共八十三页43salesman:salesman()CommRate=0.04;/销售提成比例4void salesman:pay()cout请输入namesales;accumPay=sales*CommRate;/月薪销售提成 cout推销员n
24、ame编号individualEmpNo 本月工资accumPayendl;void salesman:displayStatus()cout推销员name编号individualEmpNo “级别为”grade“级,已付本月工资”accumPayendl;本讲稿第四十三页,共八十三页44manager:manager()monthlyPay=8000;/固定月薪8000元void manager:pay()accumPay=monthlyPay;/月薪总额即固定月薪数 cout经理name编号individualEmpNo 本月工资accumPayendl;void manager:disp
25、layStatus()cout经理name编号individualEmpNo “级别为”grade“级,已付本月工资”accumPayendl;本讲稿第四十四页,共八十三页45salesmanager:salesmanager()monthlyPay=5000;CommRate=0.005;void salesmanager:pay()cout“请输入”employee:namesales;accumPay=monthlyPay+CommRate*sales;/月薪固定月 薪十销售提成 cout销售经理name编号individualEmpNo 本月工资accumPayendl;void sa
26、lesmanager:displayStatus()cout销售经理 name编号individualEmpNo “级别为”grade“级,已付本月工资”accumPayendl;本讲稿第四十五页,共八十三页46int main()manager m1;technician t1;salesmanager sm1;salesman s1;employee*emp4=&m1,&t1,&sm1,&s1;/用指针数组存放各个对象的地址 for(int i=0;i pay();/显示月薪 empi-displayStatus();/显示人员信息 return 0;本讲稿第四十六页,共八十三页47本章主
27、要内容本章主要内容多继承如何工作多继承如何工作继承的模糊性(二义性问题)继承的模糊性(二义性问题)虚基类虚基类多继承的构造顺序多继承的构造顺序保护继承与私有继承保护继承与私有继承本讲稿第四十七页,共八十三页48多继承时的构造函数派生类名:派生类名(基类1形参,基类2形参,,基类n形参,本类形参):基类名1(参数),基类名2(参数),基类名n(参数)本类成员初始化赋值语句;本讲稿第四十八页,共八十三页49多继承时的构造函数当基类中定义有默认形式的构造函数或未定义构造函数时,派生类构造函数的定义中可以省略对基类构造函数的调用,也可以不定义,全采用默认形式构造函数。当基类定义有带形参的构造函数时,派
28、生类也应定义构造函数,提供将参数传递给基类构造函数的途径。本讲稿第四十九页,共八十三页50构造函数的调用次序1 调用基类构造函数,调用顺序按照它们被继承时声明的顺序(从左向右)。2 调用成员对象的构造函数,调用顺序按照它们在类中声明的顺序。3 派生类的构造函数体中的内容。本讲稿第五十页,共八十三页51多继承且有内嵌对象时的构造函数派生类名:派生类名(基类1形参,基类2形参,基类n形参,本类形参):基类名1(参数),基类名2(参数),.基类名n(参数),对象数据成员的初始化 本类成员初始化赋值语句;本讲稿第五十一页,共八十三页52举例#includeclass B1 public:B1(int
29、i)cout“Constructing B1”iendl;class B2 public:B2(int j)cout“Constructing B2”jendl;本讲稿第五十二页,共八十三页class B3 public:B3()cout“Constructing B3*”endl;class C:public B2,public B1,public B3 /派生类 public:C(int a,int b,int c,int d):B1(a),memB2(d),memB1(c),B2(b)private:B1 memB1;B2 memB2;B3 memB3;void main()C obj(
30、1,2,3,4);本讲稿第五十三页,共八十三页调用顺序:先按派生类声明时基类的顺序调用基类的构造函数:B2、B1、B3;再按成员对象定义的顺序,调用成员对象的构造函数:B1、B2、B3程序运行结果:Constructing B22Constructing B11Constructing B3*Constructing B13Constructing B24Constructing B3*本讲稿第五十四页,共八十三页55多重继承带有虚拟基类的顺序构造对象的规则需要扩展以控制多重继承。构造函数按下列顺序被调用:(1)任何虚拟基类的构造函数按照它们被继承的顺序构造;(2)任何非虚拟基类的构造函数按照
31、它们被继承的顺序构造;(3)任何成员对象的构造函数按照它们声明的顺序调用;(4)类自己的构造函数。本讲稿第五十五页,共八十三页56class OBJ1public:OBJ1()cout OBJ1n;class OBJ2public:OBJ2()cout OBJ2n;本讲稿第五十六页,共八十三页57class Base1public:Base1()cout Base1n;class Base2public:Base2()cout Base2n;class Base3public:Base3()cout Base3n;class Base4public:Base4()cout Base4n;本讲稿
32、第五十七页,共八十三页58class Derived:public Base1,virtual public Base2,public Base3,virtual public Base4public:Derived():Base4(),Base3(),Base2(),Base1(),obj2(),obj1()cout Derived ok.n;protected:OBJ1 obj1;OBJ2 obj2;void main()Derived aa;cout 在语言中实现多继承并不容易,这主要是编译程序问题,还有模糊性问题。建议你如果可能,在进一步阅读有关参考书之前,尽量避免用多重继承。单个继承
33、提供了足够强大的功能,不一定非用多重继承不可。我们应先学会阅读一些商品化的类库源程序中有关多重继承的部分,因为那些都是经过测试的安全代码。本讲稿第六十页,共八十三页61本章主要内容本章主要内容多继承如何工作多继承如何工作多继承的构造顺序多继承的构造顺序继承的模糊性(继承的模糊性(二义性问题)二义性问题)虚基类虚基类 继承的访问控制继承的访问控制 保护继承与私有继承保护继承与私有继承 本讲稿第六十一页,共八十三页62 继承可以公共继承,也可保护继承和私有继承。对于不同的继承方式,其访问控制是不同的 本讲稿第六十二页,共八十三页63我们在前面讨论的类的继承关系都是公共继承的。在公共继承的类中,基类
34、的每个成员在子类中保持同样的访问方式。即在基类中为public的成员,子类中可以访问之,并据为public的;基类中为protected的成员,子类中也可访问之,并据为protected的;基类中为private的成员,在子类中不能访问之,这就像在应用程序中不能访问类中私有成员一样。下面的例子中的代码,是对上表的一个解释:本讲稿第六十三页,共八十三页64class Base public:int m1;protected:int m2;private:int m3;class PrivateClass:private Base /私有继承 public:void test()m1=1;/ok:
35、将m1据为private m2=2;/ok:将m2据为private m3=3;/不可访问 ;本讲稿第六十四页,共八十三页65class DerivedFromPri:public PrivateClass public:void test()m1=1;/不可访问基类的私有成员 m2=2;/不可访问 m3=3;/不可访问 ;class ProtectedClass:protected Base /保护继承 public:void test()m1=1;/ml据为protected m2=2;/m2据为protected m3=3;/不可访问 ;本讲稿第六十五页,共八十三页66class Der
36、ivedFromPro:public ProtectedClass public:void test()m1=1;/ml仍为protected m2=2;/m2仍为protected m3=3;/不可访问 ;class PublicClass:public Base /公共继承 public:void test()m1=1;/ml为public m2=2;/m2为protected m3=3;/不可访问 ;本讲稿第六十六页,共八十三页67class DerivedFromPub:public PublicClass public:void test()m1=1;/ml仍保持为 public m
37、2=2;/m2仍保持为prOtected m3=3;/不可访问 ;本讲稿第六十七页,共八十三页68void main()PrivateClass priObj;priObj.m1=1;/error priObj.m2=2;error priObj.m3=3;error ProtectedClass proObj;proObj.m1=1;/error proObj.m2=2;/error proObj.m3=3;/error PublicClass pubObj;pubObj.m1=1;pubObj.m2=2;/error pubObj.m3=3;/error 本讲稿第六十八页,共八十三页69类
38、Base包括三个成员m1,m2,m3,分别定义为public,protected,private。Base作为PrivateClass,ProtectedClass,PublicClass三个类的基类,这三个类分别用私有、保护和公共继承派生。于是在这三个类中,数据成员的性质发生了变化:私有继承时,基类中不管是公有的,还是保护的或者为私有的,一律在子类中变成私有成员。保护继承时,基类中公共和保护的成员在子类中变成保护的,而基类中私有的成员在子类中变成私有的。公共继承时,基类中为公共、保护和私有的成员在子类中仍保持为公共、保护和私有的。本讲稿第六十九页,共八十三页70m3是私有的,它只能被Base
39、访问,不能被派生类和非成员函数访问。在所有的test()函数中引用m3时将报错。m1和m2对直接从Base派生的类都可以访问。所以由Private Class:test(),ProtectedClass:test()和PublicClass:test()引用这两个成员是允许的。PrivateClass类私有继承Base,这意味着m1和m2对PrivateClass中的成员现在可以私有访问。因而不能被像DerivedFromPri一样由PrivateClass直接派生的类访问。ProtectedClass类被保护地继承Base,这使得m1和m2都被保护。对ProtectedClass:test(
40、)和DerivedFromPro:test()这两个成员都是可访问的。本讲稿第七十页,共八十三页71 PublicClass类公共继承Base。在PublicClass中三个成员都保持它们在Base中的访问特性。如果不标明继承为公共还是保护或者私有,则默认的继承是私有。但最好不要依赖默 认,如果把继承类型表示清楚,则程序的可读性会更好。在单个类中,protected和private没有什么区别。但在继承关系中,基类的但在继承关系中,基类的private成员不但对应成员不但对应用程序隐藏,甚至对派生类也隐藏。而基类的用程序隐藏,甚至对派生类也隐藏。而基类的保护成员则只对应用程序隐藏,而对派生类则
41、保护成员则只对应用程序隐藏,而对派生类则毫不隐瞒。毫不隐瞒。本讲稿第七十一页,共八十三页72本章主要内容本章主要内容多继承如何工作多继承如何工作多继承的构造顺序多继承的构造顺序继承的模糊性(继承的模糊性(二义性问题)二义性问题)虚基类虚基类 继承的访问控制继承的访问控制 保护继承与私有继承保护继承与私有继承 本讲稿第七十二页,共八十三页73 一个私有的或保护的派生类不是子类,因为非公共的派生类不能做基类能做的所有的 事。例如,下面的代码定义了一个私有继承基类的类 本讲稿第七十三页,共八十三页74class Animal public:Animal()void eat()couteatn;cla
42、ss Giraffe:private Animal public;Giraffe()void StrechNeck(double)coutstrech neck n;class Cat:public Animal Cat()Void Meaw()coutmeawn;本讲稿第七十四页,共八十三页75void Func(Animal&an)an.eat();void main()Cat dao;Giraffe gir;Func(dao);Func(gir);error 本讲稿第七十五页,共八十三页76函数Func()要用一个Animal类型的对象,但调用Func(dao)实际上传递的是Cat类的对
43、象。因为Cat是公共继承Animal类,所以Cat类对象拥有Animal的所有成员的使用。Animal 对象可以做的事,Cat对象也可以做。但是,对于gir对象就不一样。Giraffe类私有继承了Animal类,意味着对象gir不能直接访问Animal类的成员。其实,在gir对象空间中,包含有Animal类的对象,只是无法让其公开访问。本讲稿第七十六页,共八十三页77 例如,下面的代码中,Giraffe继承了Animal类,Giraffe的成员函数可以访问像Animal对象那样访问其Animal成员:本讲稿第七十七页,共八十三页78class Animalpublic:Animal()void
44、 eat()cout eat.n;class Giraffe:private Animalpublic:Giraffe()void StretchNeck()cout stretch neck.n;void take()eat();/ok;本讲稿第七十八页,共八十三页79void Func(Giraffe&an)an.take();void main()Giraffe gir;gir.StretchNeck();Func(gir);/ok运行结果为:stretch neck eat本讲稿第七十九页,共八十三页80保护继承与私有继承类似,继承之后的类相对于基类来说是独立的;保护继承的类对象,在公
45、开场合同样不能使用基类的成员 本讲稿第八十页,共八十三页81class Animal public:Animal()void eat()couteatn;class Giraffe:protected Animal Giraffe()void StrechNeck(double)coutstrechneckn;void take()eat();ok ;void main()Giraffe gir;gir.eat();error gir.take();ok gir.StretchNeck();本讲稿第八十一页,共八十三页82派生类的三种继承方式小结:公有继承public)、私有继承(private)和保护继承(protected)是常用的三种继承方式。本讲稿第八十二页,共八十三页831对于公有继承方式:在公有继承时,派生类的对象可以访问基类中的公有成员;派生类的成员函数可以访问基类中的公有成员和保护成员。2对于私有继承方式:在私有继承时,基类的成员只能由直接派生类访问,而无法再往下继承。3对于保护继承方式:在保护继承时,基类的成员也只能由直接派生类访问,而无法再往下继承 本讲稿第八十三页,共八十三页
限制150内