乍听虚继承,吓倒很多人!!
或许很多人会认为这和虚函数有关,其实,几乎没有任何关系。它的出现,是为了克服继承中一个非常棘手的问题,也就是臭名昭著的菱形继承(二义性)问题。
二义性,也就是说,假如我们有一个基类:
class Dog //狗,虚基类
{
public:
int getWeight()
{
return m_nWeight;
}
protected:
int m_nWeight;
};
class OrientDog : public Dog //东方的狗,继承自Dog
{
};
class WhiteDog : public Dog //白狗,继承自Dog
{
};
class myDog : public OrientDog, public WhiteDog //我的狗,是一条东方的白狗
{
public:
myDog(int weight)
{
m_nWeight = weight; //error C2385: 'myDog::m_nWeight' is ambiguous
}
};
在我们编译的时候,会发现myDog的构造函数,无法编译通过。编译器说:myDog::m_nWeight这个成员变量不能唯一确定。
为什么?
这就是由于多重继承所带来的二义性,其实也就是所谓的菱形继承。下面是继承图:
Dog
/ \
OrientDog WhiteDog
\ /
myDog
这样的继承结构,导致myDog重复继承了基类Dog的数据成员m_nWeight以及非虚的成员函数getWeight(),也就是说,在派生类myDog里,存在了两个m_nWeight成员变量和两个getWeight()成员函数,从而myDog无法辨认哪个到底应该是正统的,正所谓一山容不得二虎,我们必须要想个办法,把这种混乱不堪的行为整顿一下。
怎么办?
快刀斩乱麻,告诉编译器,在遇到这样的情况时,只选择第一个出现的成员就可以了,剔除掉以后所有的,从而就引进了虚拟继承的机制。也就是在继承属性前加上关键字virtual,就可以轻松的办到这一切。现在,我们重写OrigentDog和WhiteDog这两个中间类:
class OrientDog : virtual public Dog //东方的狗,继承自Dog
class WhiteDog : virtual public Dog //白狗,继承自Dog