11.16C++虚基类详解.doc_第1页
11.16C++虚基类详解.doc_第2页
11.16C++虚基类详解.doc_第3页
11.16C++虚基类详解.doc_第4页
11.16C++虚基类详解.doc_第5页
全文预览已结束

下载本文档

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

文档简介

我们知道,如果一个派生类有多个直接基类,而这些直接基类又有一个共同的基类,则在最终的派生类中会保留该间接共同基类数据成员的多份同名成员。在引用这些同名的成员时,必须在派生类对象名后增加直接基类名,以避免产生二义性,使其惟一地标识一个成员,如: c1.A:display( )在一个类中保留间接共同基类的多份同名成员,虽然有时是有必要的,可以在不同的数据成员中分别存放不同的数据,也可以通过构造函数分别对它们进行初始化。但在大多数情况下,这种现象是人们不希望出现的。因为保留多份数据成员的拷贝,不仅占用较多的存储空间,还增加了访问这些成员时的困难,容易出错。而且在实际上,并不需要有多份拷贝。C+提供虚基类(virtualbaseclass)的方法,使得在继承间接共同基类时只保留一份成员。假设类D是类B和类C公用派生类,而类B和类C又是类A的派生类,如图11.21所示。 设类A有数据成员data和成员函数fun;派生类B和C分别从类A继承了data和fun,此外类B还增加了自己的数据成员data_b,类C增加了数据成员data_c。如果不用虚基类,就会在类D中保留了类A成员data的两份拷贝,分别表示为int B:data和int C:data。同样有两个同名的成员函数,表示为void B:fun()和void C:fun()。类B中增加的成员data_b和类C中增加的成员dat_c不同名,不必用类名限定。此外,类D还增加了自己的数据成员data_d和成员函数fun_d。图 11.21现在,将类A声明为虚基类,方法如下:. classA/声明基类A. . / 代码. ;. classB:virtualpublicA/声明类B是类A的公用派生类,A是B的虚基类. . / 代码. ;. classC:virtualpublicA/声明类C是类A的公用派生类,A是C的虚基类. . / 代码. ;注意: 虚基类并不是在声明基类时声明的,而是在声明派生类时,指定继承方式时声明的。因为一个基类可以在生成一个派生类时作为虚基类,而在生成另一个派生类时不作为虚基类。声明虚基类的一般形式为: class 派生类名: virtual 继承方式 基类名即在声明派生类时,将关键字 virtual 加到相应的继承方式前面,经过这样的声明后,当基类通过多条派生路径被一个派生类继承时,该派生类只继承该基类一次,也就是说,基类成员只保留一次。需要注意:为了保证虚基类在派生类中只继承一次,应当在该基类的所有直接派生类中声明为虚基类。否则仍然会出现对基类的多次继承。如果在派生类B和C中将类A声明为虚基类,而在派生类D中没有将类A声明为虚基类,则在派生类E中,虽然从类B和C路径派生的部分只保留一份基类成员,但从类D路径派生的部分还保留一份基类成员。虚基类的初始化如果在虚基类中定义了带参数的构造函数,而且没有定义默认构造函数,则在其所有派生类(包括直接派生或间接派生的派生类)中,通过构造函数的初始化表对虚基类进行初始化。例如. classA/定义基类A. . A(inti)/基类构造函数,有一个参数;. classB:virtualpublicA/A作为B的虚基类. . B(intn):A(n)/B类构造函数,在初始化表中对虚基类初始化. ;. classC:virtualpublicA/A作为C的虚基类. . C(intn):A(n)/C类构造函数,在初始化表中对虚基类初始化. ;. classD:publicB,publicC/类D的构造函数,在初始化表中对所有基类初始化. . D(intn):A(n),B(n),C(n). ;注意: 在定义类D的构造函数时,与以往使用的方法有所不同。以往,在派生类的构造函数中只需负责对其直接基类初始化,再由其直接基类负责对间接基类初始化。现在,由于虚基类在派生类中只有一份数据成员,所以这份数据成员的初始化必须由派生类直接给出。如果不由最后的派生类直接对虚基类初始化,而由虚基类的直接派生类(如类B和类C)对虚基类初始化,就有可能由于在类B和类C的构造函数中对虚基类给出不同的初始化参数而产生矛盾。所以规定:在最后的派生类中不仅要负责对其直接基类进行初始化,还要负责对虚基类初始化。有的读者会提出:类D的构造函数通过初始化表调了虚基类的构造函数A,而类B和类C的构造函数也通过初始化表调用了虚基类的构造函数A,这样虚基类的构造函数岂非被调用了3次?大家不必过虑,C+编译系统只执行最后的派生类对虚基类的构造函数的调用,而忽略虚基类的其他派生类(如类B和类C) 对虚基类的构造函数的调用,这就保证了虚基类的数据成员不会被多次初始化。虚基类的简单应用举例例11.9 在例11. 8(具体代码请查看:C+类的多重继承)的基础上,在Teacher类和Student类之上增加一个共同的基类Person。作为人员的一些基本数据都放在Person中,在 Teacher类和Student类中再增加一些必要的数据。可写出以下程序:. #include. #include. usingnamespacestd;. /声明公共基类Person. classPerson. . public:. Person(stringnam,chars,inta)/构造函数. . name=nam;. sex=s;. age=a;. . protected:/保护成员. stringname;. charsex;. intage;. ;. /声明Person的直接派生类Teacher. classTeacher:virtualpublicPerson/声明Person为公用继承的虚基类. . public:. Teacher(stringnam,chars,inta,stringt):Person(nam,s,a)/构造函数. . title=t;. . protected:/保护成员. stringtitle;/职称. ;. /声明Person的直接派生类Student. classStudent:virtualpublicPerson/声明Person为公用继承的虚基类. . public:. Student(stringnam,chars,inta,floatsco)/构造函数. :Person(nam,s,a),score(sco)/初始化表. protected:/保护成员. floatscore;/成绩. ;. /声明多重继承的派生类Graduate. classGraduate:publicTeacher,publicStudent/Teacher和Student为直接基类. . public:. Graduate(stringnam,chars,inta,stringt,floatsco,floatw)/构造函数. :Person(nam,s,a),Teacher(nam,s,a,t),Student(nam,s,a,sco),wage(w). /初始化表. voidshow()/输出研究生的有关数据. . coutname:nameendl;. coutage:ageendl;. coutsex:sexendl;. coutscore:scoreendl;. couttitle:titleendl;. coutwages:wageendl;. . private:. floatwage;/工资. ;. /主函数. intmain(). . Graduategrad1(Wang-li,f,24,assistant,89.5,1234.5);. grad1.show();. return0;. 对程序的两点说明:1) 请注意各类的构造函数的写法。在Person类中定义了包含3个形参的构造函数,用它对数据成员name、sex和age进行初始化。在Teacher和Student类的构造函数中,按规定要在初始化表中包含对基类的初始化,尽管对虚基类来说,编译系统不会由此调用基类的构造函数,但仍然应当按照派生类构造函数的统一格式书写。在最后派生类Graduate的构造函数中,既包括对虚基类构造函数的调用,也包括对其直接基类的初 始化。2) 在Graduate类中,只保留一份基类的成员,因此可以用Graduate类中的show函数引用Graduate类对象中的公共基类Person的数据成员name、sex、age的值,不需要加基类名和域运算符(:),不会产生二义性。可以看到:使用多重继承时要十分小心,经常会出现二义性问题。前面介绍的例子是简单的,如

温馨提示

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

评论

0/150

提交评论