C++继承的问题 : 菱形继承 (虚拟继承)

上一次我们学习了继承相关的知识, 这次我们来看看继承的问题 — 菱形继承.

一. 什么是菱形继承

一图流解释
在这里插入图片描述

二. 菱形继承的问题

就拿上面的经典菱形继承来说, 从下面的对象成员模型构造,可以看出菱形继承有数据冗余和二义性的问题。在D类的对象中A类成员会有两份。

.

下面给出菱形继承的代码 :

//菱形继承
class AA {
public:
	int _aa;
};

class BB : public AA {   //AA::_aa
public:
	int _bb;
};

class CC : public AA {   //AA::_aa
public:
	int _cc;
};

class DD : public BB, public CC {   //BB::_a   CC::_a
public:
	int _dd;
};

我们可以通过调试看一下DD类对象的数据模型
内存按照继承顺序排列 : 先存放继承的父类(按顺序), 然后存放自己的成员

在这里插入图片描述
可以通过一下代码给d对象赋值

	d.BB::_aa = 1;
	d._bb = 2;
	d.CC::_aa = 5;
	d._cc = 3;
	d._dd = 4;

菱形继承: 公共的基类成员会存在两份, 数据冗余, 且使用时要加作用域, 比较麻烦

在这里插入图片描述
通过显示指定访问哪个父类的成员可以解决二义性问题,但是数据冗余问题无法解决

下面是d对象的内存窗口, 一行显示4字节, 可以看到我写的成员变量顺序就是他在内存中排布的顺序
在这里插入图片描述

三. 虚拟继承

虚拟继承解决数据冗余和二义性的原理

拿上面的例子来说, 定义方式是B, C继承A的时候, 在继承方式前面加上virtual关键字

代码如下 :

//菱形继承
class AA {
public:
	int _aa;
};

class BB : virtual public AA {  
public:
	int _bb;
};

class CC : virtual public AA {  
public:
	int _cc;
};

class DD : public BB, public CC { 
public:
	int _dd;
};

为了研究虚拟继承如何解决数据冗余的问题, 我们来看看他的内存分布

下面是虚拟继承下的d对象内存分布情况 :

在这里插入图片描述

我们可以看到, 本来BB::_aa 和 CC::_aa 位置的数据变了, 这个数据没有什么规律, 这其实是两个指针, 叫做虚基表指针, 指向两个虚基表, 虚基表中存放着偏移量, 可以通过这个偏移量找到数据_aa

我的机器是小端字节序, 低地址存数据的低位
那么这两个地址转换过来就是 0x00feec280x00feed00
在这里插入图片描述

在这里插入图片描述

通过内存窗口的变化, 我们可以看到, 现在数据_aa存在下面的标红地址处
在这里插入图片描述

这么一看, 上面的偏移量 + 地址 正好就是FD74这个内存地址

这样就解决了数据冗余的问题, 使得_aa只存在一份, 下面我们运行代码看一波

	d.BB::_aa = 1;
	d._bb = 2;
	d.CC::_aa = 5;
	d._cc = 3;
	d._dd = 4;

	d._aa = 8;

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
可以看到, 用了虚拟继承之后, BB::_aa 和CC::_aa, 与直接用_aa改变的是同一块内存空间, 说明_aa只有一份

OK, 菱形继承的问题就说到这

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

殇&璃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值