1、虚基类的作用从上面的介绍可知:如果一个派生类有多个直接基类,而这些直接基类又有一个共同的基类,则在最终的派生类中会保留该间接共同基类数据成员的多份同名成员。
在引用这些同名的成员时,必须在派生类对象名后增加直接基类名,以避免产生二义性,使其惟一地标识一个成员,如
c1.A::display( )。
在一个类中保留间接共同基类的多份同名成员,这种现象是人们不希望出现的。C++提供虚基类(virtual base class
)的方法,使得在继承间接共同基类时只保留一份成员。
现在,将类A声明为虚基类,方法如下:
class
A//声明基类A
{…};
class B :virtual public
A//声明类B是类A的公用派生类,A是B的虚基类
{…};
class C :virtual public
A//声明类C是类A的公用派生类,A是C的虚基类
{…};
注意:
虚基类并不是在声明基类时声明的,而是在声明派生类时,指定继承方式时声明的。因为一个基类可以在生成一个派生类时作为虚基类,而在生成另一个派生类时不作为虚基类。
声明虚基类的一般形式为
class 派生类名: virtual 继承方式
基类名
经过这样的声明后,当基类通过多条派生路径被一个派生类继承时,该派生类只继承该基类一次。
需要注意:
为了保证虚基类在派生类中只继承一次,应当在该基类的所有直接派生类中声明为虚基类。否则仍然会出现对基类的多次继承。
如果在派生类B和C中将类A声明为虚基类,而在派生类D中没有将类A声明为虚基类,则在派生类E中,虽然从类B和C路径派生的部分只保留一份基类成员,但从类D路径派生的部分还保留一份基类成员。
2、虚基类的初始化如果在虚基类中定义了带参数的构造函数,而且没有定义默认构造函数,则在其所有派生类(包括直接派生或间接派生的派生类)中,通过构造函数的初始化表对虚基类进行初始化。例如
class
A//定义基类A
{
A(int i){ } //基类构造函数,有一个参数};
class B :virtual public A
//A作为B的虚基类
{
B(int n):A(n){ } //B类构造函数,在初始化表中对虚基类初始化
};
class C
:virtual public A //A作为C的虚基类
{
C(int n):A(n){ }
//C类构造函数,在初始化表中对虚基类初始化
};
class D :public B,public C
//类D的构造函数,在初始化表中对所有基类初始化
{
D(int n):A(n),B(n),C(n){ }
};
注意:
在定义类D的构造函数时,与以往使用的方法有所不同。规定:
在最后的派生类中不仅要负责对其直接基类进行初始化,还要负责对虚基类初始化。C++编译系统只执行最后的派生类对虚基类的构造函数的调用,而忽略虚基类的其他派生类(如类B和类C)
对虚基类的构造函数的调用,这就保证了虚基类的数据成员不会被多次初始化。
温馨提示:使用多重继承时要十分小心,经常会出现二义性问题。许多专业人员认为:不要提倡在程序中使用多重继承,只有在比较简单和不易出现二义性的情况或实在必要时才使用多重继承,能用单一继承解决的问题就不要使用多重继承。也是由于这个原因,有些面向对象的程序设计语言(如Java,Smalltalk)并不支持多重继承。