从内存的角度窥探C++多继承中的菱形继承问题

1. 什么是菱形继承

菱形继承就是继承的方式长得像个菱形而已,它是多继承中一种比较特殊的存在;
比如下面的类关系之间的设计:
student 和 worker 类 继承了 person 类,而 undergraduate 继承了 student 和 worker 这两个类;这个继承的图很像菱形,咋们说它是菱形继承;
在这里插入图片描述


2. 菱形继承会带来什么问题

菱形继承会带来数据访问的二义性和数据冗余的问题;

注意

这个数据访问的二义性是发生在菱形继承最底下的类上;

数据冗余的问题也是发生在菱形继承最底下的类上;


比如:该继承体系下的最底下类的对象模型中:

undergraduate 对象中 m_age就占了两份数据,一份来自 student 和一份来自 worker 的,对于undergraduate来说,是没有必须有这两份数据的,这就导致了 undergraduate类中有数据冗余,也就是 m_age这个数据冗余了;
在这里插入图片描述


而二义性的体现在于:当我定义了一个最底下类的对象时候,也就是Undergraduate ug; ,通过:ug.m_age会导致二义性的存在:也就是不知道访问的到底是student 的m_age 呢 还是 worker的m_age 呢?

虽然我们可以通过:ug.Student::m_age; 和 ug.Woker::m_age 方式来解决数据的二义性问题;但是已经没有解决m_age在ug对象中数据冗余的问题;


代码验证一下:菱形继承带来的二义性和数据冗余的问题:

注意:为了方便说明:我是用 struct 来定义类:因为这是默认成员是共有的,比较容易说明我要讲得问题;

#include<iostream>
using namespace std;

struct Person{
	int m_age;
};
struct Student:public Person{
	int m_score;
};
struct Worker:public Person{
	int m_salary;
};
struct Undergraduate:public Student,public Worker{
	int m_grade;
};

int main(){
	Undergraduate ug;
	ug.m_age = 20;
	getchar();
	return 0;
}

编译直接报错:这里就是在验证菱形继承带来的二义性问题;
在这里插入图片描述


解决方案:指明作用域去访问即可:
在这里插入图片描述
这样编译就会成功;


但是二义性解决了,数据冗余问题依旧没解决,ug对象中依旧有两份m_age;并且我们从感性理解,ug对象不需要两份m_age,这个设计本身就是不合理的;

窥探监视窗口:我们客户以看出确实是在ug对象中有两份m_age;这是不合理的设计;在这里插入图片描述


3. 虚继承的方式解决菱形继承数据冗余和二义性的问题

所以基于以上对菱形继承的分析,我们C++ 就有一种虚继承的方式来解决菱形继承带来的问题;
虚继承的方式很简单:我们只要在菱形继承的图中中间部分使用virtual 关键字去虚继承就可以解决这个问题:
在这里插入图片描述

#include<iostream>
using namespace std;

struct Person{
	int m_age;
};
struct Student:virtual public Person{ //虚继承
	int m_score;
};
struct Worker:virtual public Person{//虚继承
	int m_salary;
};
struct Undergraduate:public Student,public Worker{
	int m_grade;
};

int main(){

	Undergraduate ug;
	ug.m_age = 20; //访问无问题,解决了二义性的问题
	/*ug.Student::m_age = 20;
	ug.Worker::m_age = 30;*/

	getchar();
	return 0;
}

4. 通过内存窥探菱形继承的对象模型

我们通过内存窥探一下ug里面有什么:
在这里插入图片描述


我们可以发现:上面内存的窥探图:可以总结一下的表格查看:

在这里插入图片描述
在这里插入图片描述
这里的20表示:在student的虚表指针,和冗余数据的m_age成员变量,偏移字节数为20;
这里的12便是:在worker的虚表指针,和冗余数据的m_age的成员变量,偏移的字节数为12;
一旦有了虚继承,咋们的m_age就在ug对象只有一份,而访问m_age的方式就是通过上面虚表指针的偏移量去找到的;


通过虚表指针,我们就可以通过偏移量找到了数据冗余的变量m_age,并且解决它冗余且二义性的问题;


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

呋喃吖

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

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

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

打赏作者

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

抵扣说明:

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

余额充值