菱形虚拟继承的深入剖析

继承是面向对象语言的一大特性,在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的位移,也就是我们所说的偏移量。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值