虚继承的概念
一般,不希望在一个派生类中存在某个公共基类的多个同名的成员变量。虽然也可以通过在成员变量名前面加上“类名::”消除其二义性,但解决这个问题的最好办法是使用虚继承。虚继承方法可以保证在任何一个存在公共基类的派生类中,不会存在一个以上的同名成员变量。
所谓虚继承,就是说一个类层次中,如果某个派生类存在一个公共基类,将这个基类设置为虚继承,这时从不同的路径继承过来的该类成员在内存中只保留一份拷贝。因此,虚继承方法可以消除成员变量的二义性。
注意:虚继承并不是在声明基类时声明的,而是在声明派生类时,指定继承方式时声明的。因为一个基类可以在生成一个派生类作为虚继承,而在生成另一个派生类时不作为虚继承。声明虚继承的一般形式为:
class 派生类名:virtual 继承方式 基类名
即在声明派生类时,将关键字virtual加到相应的继承方式前面,经过这样的声明后,当基类通过多条派生路径被一个派生类继承时,该派生类只继承该基类一次,也就是基类成员只保留一次。
需要注意:为了保证虚继承在派生类中继承一次,应当在该基类的所有直接派生类中声明为虚继承。否则仍然会出现对基类的多继承。
例:虚继承的使用。
#include <iostream.h>
class A
{
public:
A()
{
a = 7;
cout << "A class a=" << a << endl;
}
protected:
int a;
};
class B: virtual public A
{
public:
B()
{
a = a + 10;
cout << "B class a=" << a << endl;
}
};
class C : virtual public A
{
public:
C()
{
a = a + 20;
cout << "C class a=" << a << endl;
}
};
class D : public C, public B
{
public:
D()
{
cout << "D class a=" << a << endl;
}
};
void main()
{
D obj;
}
虚继承的初始化
虚继承的初始化与一般的多继承的初始化在语法上是一样的,但构造函数的调用顺序不同。要注意以下几点:
① 如果在虚继承中定义有带形参的构造函数,并且没有定义缺省形式的构造函数,则整个继承结构中,所有直接或间接的派生类都必须在构造函数的成员初始化表中列出对虚基类构造函数的调用,以初始化在虚基类中定义的数据成员。例如:
class 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(int n) : A(n), B(n), C(n) {} //类D的构造函数,注意对虚继承类A也要做初始化
.