菱形继承的内存布局是怎么回事呢?访问时,又会出现什么情况?

首先,我们看一下菱形继承(也叫钻石继承)的类之间的关系,如下图:
这里写图片描述
这样的话,那D类有两个B类成员吗?,访问的话岂不是两个同名吗?那我们验证一下,
用代码表示的话就是:

//菱形继承
#include<iostream>
using namespace std;
//基类B
class B
{
public:
    int _b;

};
//基类C1,公有继承B
class C1 :public B
{
public:
    int _c1;
};
//基类C2,公有继承B
class C2 :public B
{
public:
    int _c2;
};
//派生类D
class D :public C1, public C2
{
public:
    int _d;

};

void FunTest1()
{

    D d;
    //d._b;//d对象空间中公有继承C1,C2,故有两个_b,构成二义性,计算机无法识别
    cout << sizeof(D) << endl;//20
    d.C1::_b = 1;
    d._c1 = 2;
    d.C2::_b = 3;
    d._c2 = 4;
    d._d = 5;

}
int main()
{

    FunTest1();

    return 0;
}

如果我们直接调用d._b=1时,就会发现调用失败
这里写图片描述
对象d的大小为20个字节,那是怎么来的呢?
d对象空间中公有继承C1,C2,各占8个字节,加上自己的成员变量_d总共20个字节,并且C1、C2都是公有继承B,也就是说有两个_b在d对象中也是都可以访问的,那岂不是构成二义性,计算机无法识别
好的,访问用作用域限定符解决这个问题,
那它的内存布局又是怎么回事呢?
我们对每个成员进行赋值,打开内存&d,看一下究竟:
这里写图片描述
那这样的话,一个对象就有了两个基类对象B,而我们有时候往往只需要一个怎么办,那又怎样解决这个数据冗余问题呢?
虚继承:在派生类要继承方式前面加上virtual关键字:针对于这个问题,我们基于上面的代码稍加修改即可:

//菱形继承
#include<iostream>
using namespace std;

class B
{
public:
    int _b;

};
class C1 :virtual public B//请留意此处
{
public:
    int _c1;
};
class C2 :virtual public B//请留意此处
{
public:
    int _c2;
};

class D :public C1, public C2
{
public:
    int _d;

};

void FunTest1()
{
    D d;
    d._b=1;//此时我们会发现二义性的问题消失了,我们对他进行赋值
    d._c1 = 2;
    d._c2 = 3;
    d._d = 4;
    cout << sizeof(D) << endl;//24
}
int main()
{
    FunTest1();
    return 0;
}

此时对象d的大小变为了24个字节,那他又是怎么来的,公有继承,但又是怎么解决这个_b成员二义性的问题呢?
我们对它的各个成员进行赋值,&d查看一下他的内存布局是怎么回事?
如下:
这里写图片描述
看起来像一个指针,我们打开内存看一下结构,似乎数字有些含义:
这里写图片描述
我们再看c1里面的指针:
这里写图片描述
通过程序调用结果,我们发现二义性的问题得到了解决,看来这个指针就是来解决二义性的问题:那他的所指的内容又是怎么解决这个问题呢?
我们看一下汇编:
这里写图片描述
这里写图片描述
[eax+4]->ecx取到0x14,然后把1放到该偏移量对应的地址中,我们发现此时_b被修改了。0x14就是偏移量,
同理,我们可以知道C2的指针指向的内容为_b相对于自己的偏移量为0x c。系统凭借偏移量就可以将两份一样的对象变成了一个,我们用对象d直接访问_b也是指向同一块内存。因此解决了而二义性的问题。‘

当然结构体的大小为24我们也就明白了。’(见上图内存布局图)

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值