C++多重继承与虚继承

多重继承

一个简单的例子(非虚拟)

class Top
{
    public: int a;
}; 
class Left : public Top
{ 
    public: int b;
}; 
class Right : public Top
{ 
    public: int c;
}; 
class Bottom : public Left, public Right
{ 
    public: int d;
};

使用UML图,我们可以把这个层次结构表示为:



注意Top被继承了两次。这意味着类型Bottom的一个实例bottom将有两个叫做a的元素(分别为bottom.Left::a 和 bottom.Right::a)。


Left、Right 和 Bottom在内存中是如何布局的,让我们先看一个简单的例子。Left
和 Right拥有如下的结构:

Left Right
Top::a Top::a
left::b right::c

请注意第一个属性是从Top继承下来的。这意味着在下面两条语句后

Left* left = new Left();
Top* top = left;

Left 和 Top指向了同一地址,我们可以把Left Object当成Top Object来使用(很明显,Right与此也类似)。那Buttom呢?GCC的建议如下:

Buttom
Left::Top::a
Left::b
Right::Top::a
Right::c
Bottom::d

如果我们提升Bottom指针,会发生什么事呢?

Bottom* bottom = new Bottom();
Left* left = bottom;

这段代码工作正常。我们可以把一个Bottom的对象当作一个Left对象来使用,因为两个类的内存部局是一样的。那么,如果将其提升为Right呢?会发生什么事?

Right* right = bottom;

为了执行这条语句,我们需要判断指针的值以便让它指向Bottom中对应的段。

Bottom
Left::Top::a
Left::b
right --> Right::Top::a
Right::c
Bottom::d

经过这一步,我们可以像操作正常Right对象一样使用right指针访问bottom。虽然,bottom与right现在指向两个不同的内存地址。出于完整性的缘故,思考一下执行下面这条语句时会出现什么状况。

Top* top = bottom;

是的,什么也没有。这条语句是有歧义的:编译器将会报错。

error: `Top' is an ambiguous base of `Bottom'

两种方式可以避免这样的歧义

Top* topL = (Left*) bottom;
Top* topR = (Right*) bottom;

执行这两条语句后,topL 和 left会指向同样的地址,topR 和 right也会指向同样的地址。


虚拟继承

为了避免重复继承Top,我们必须虚拟继承Top:

class Top
{ 
    public: int a;
}; 
class Left : virtual public Top
{ 
    public: int b;
}; 
class Right : virtual public Top
{ 
    public: int c;
}; 
class Bottom : public Left, public Right
{ 
    public: int d;
};

这就得到了如下的层次结构:



虽然从程序员的角度看,这也许更加的明显和简便,但从编译器的角度看,这就变得非常的复杂。重新考虑下Bottom的布局,可能是:

Bottom
Left::Top::a
Left::b
Right::c
Bottom::d

这个布局的优点是,布局的第一部分与Left的布局重叠了,这样我们就可以很容易的通过一个Left指针访问 Bottom类。


未完待续。。。
摘抄自 开源中国

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

友情链接更多精彩内容