菱形虚拟继承的深入剖析

来源:互联网 发布:数据库一体机 编辑:程序博客网 时间:2024/05/22 05:31

继承是面向对象语言的一大特性,在C++中既有单继承,当然也会存在多继承。那么多继承是怎么实现的及多继承的一些缺点,将是这篇博客想要说的内容。

多继承最典型的一个例子就是菱形继承,那什么又是菱形继承呢?就是有两个子类分别继承一个父类,而有存在一个子类同时这两个子类。图示如下。
这里写图片描述

class A{public:    int a;};class B : public A{public :    int b;};class C : public A{public:    int c;};class D : public B, public C{public:    int d;};int main(){    D d;    system("pause");    return 0;}

当我们模拟出菱形继承想给a赋值时,就会发现一个问题,我们到底是从哪个类去访问的BaseClass中的a?这时就会产生二义性。也就是说在内存中会出现两个BaseClass,结构图如下。

结构图

内存中

代码运行后调监视窗口如上,可明显看到d中存在了两个a,这也会存在数据冗余的问题。那怎么去解决这个问题?此时,C++又提出了另一个新概念——虚拟继承。虚拟继承使得在继承间接共同基类的时候只保留一份成员。接下来的篇幅将会说明虚拟继承的实现。

class A{public:    int a;};class B : virtual public A{public :    int b;};class C : virtual public A{public:    int c;};class D : public B, public C{public:    int d;};int main(){    D d;    d.B::a = 0;    d.C::a = 1;    d.B::b = 2;    d.C::c = 3;    d.D::d = 4;    cout << (sizeof(d)) << endl;    system("pause");    return 0;}

运行上述代码后,在内存中会出现以下的情形,如下图。
这里写图片描述

原来大小为20的d如今变成了24,按理说当我们采用了虚拟继承,解决了数据冗余问题,所占的空间应该也会变小,但如今反而变大了,这是怎么回事呢?

我们在细看第一行和第三行,发现了这两个数字比较接近,仔细看更像是一个地址。于是,在内存中查看会发现如下图所示的情形。

这里写图片描述

在这两个内存紧挨着的地方,出现了一个“14”和“0c”,也就是说在这个地方存了这两个数字。那么我们就可以猜测一下,在虚拟继承中,菱形继承的结构是如下图的。

这里写图片描述

BaseClass并不是按照我们所想象那样存在最上面的,而是存放在最底下,而原来存BaseClass的地方存了两个“数字”。仔细观察,不难发现这两个数字是距离BaseClass的位移,也就是我们所说的偏移量。

其实,讲到这里的时候,大家应该也就明白了,在虚拟继承中是通过存储基类的偏移量来解决数据冗余的问题,以空间换时间解决菱形继承存在的问题。

0 0
原创粉丝点击