一、整体代码
01.cpp
#include <iostream>
using namespace std;
class Parent
{
public:
int p_; // p将会被所有的子类继承,也将是二义性的根源
Parent(int p):p_(p)
{
cout<<"Parent ..."<<endl;
}
};
class Child1 :virtual public Parent
{
public:
Child1(int p) : Parent(p)
{
cout<<"Child1 ..."<<endl;
p_ =3; // p在子类Child1中被赋值为12
}
};
class Child2 :virtual public Parent
{
public:
Child2(int p) : Parent(p)
{
cout<<"Child2 ..."<<endl;
p_=5; // p在子类Child2中被赋值为13
}
};
class GrandChild : public Child2, public Child1
{
public:
int grandchild;
// p显然也存在于GrandChild中,但是到底是12,还是13呢?这就产生了二义性
GrandChild(int p) : Child1(p),Child2(p),Parent(p)//此处必须要加上Parent(p)
{
cout<<"GrandChild ..."<<endl;
grandchild = 14;
}
};
int main(void)
{
GrandChild* pGC = new GrandChild(4);
cout << pGC->p_<< endl;
delete pGC;
return 0;
}
二、运行结果
Parent ...
Child2 ...
Child1 ...
GrandChild ...
3
class GrandChild : public Child2, public Child1
结果如下:
Parent ...
Child2 ...
Child1 ...
GrandChild ...
5
三、解释
虚继承,就是在被继承的类前面加上virtual关键字,这时被继承的类称为虚基类,如下面代码中的base类。虚继承在多重继承的时可以防止二义性。
首先调用Parent的构造函数,然后调用Child1,Child2构造函数,先调用哪个后调用哪个取决与继承时候的先后顺序,如上面的结果显示。调用Child1,Child2构造函数,不再重新调用初始化参数Parent(p)。Parent(p)只被调用一次,并且一定要在GrandChild类构造时候调用Parent类的构造函数。
其实多继承本身不会出现问题,一个孙子类继承两个父亲类无所谓,但是那两个父亲类又继承于同一个爷爷类,这时候就麻烦了,因为最上面的爷爷类会被重复构造二次。为了解决这个问题引入了虚继承,并且孙子类要调用爷爷类的构造函数。这样在父亲类构造时候就不再调用爷爷类构造函数,爷爷类只构造一次。