虚继承——解决菱形继承的问题以及其底层实现

为什么要有虚继承?

在c++中我们有一种继承方式叫做菱形继承,通俗来说就是有两个类(son1,son2)都继承了同一个类(base),然后又有一个类(grandson)来继承这两个类(就是多继承的一种,个人不建议在实际开发中使用多继承)。

但是这样做会带来两个问题

  1. son1继承了base,son2也继承了base,当grandson继承son1和son2时并使用了其中的数据时,便会产生二义性。例如:base中有一个成员m_a,那么son1和son2中都有这个m_a,这个时候grandson由于继承了son1和son2,那grandson里面就会有两个m_a,当你在grandson创建的对象中使用这个m_a的时候,如果不用作用域加以修饰的话,编译器很难分清你是使用son1中的m_a还是son2中的m_a,这个时候编译器就会报错。
  2. 由于grandson继承了son1和son2,将代表着grandson中有着两份base的数据,这就导致了资源的浪费。

或许这样看不是很清楚,我们上代码看看

class base {
public:
	int m_a;
};

class son1:public base{};
class son2:public base{};
class grandson :public son1, public son2{};

int main()
{
	grandson g;
	g.m_a = 10;//这里就会报错,提示m_a不明确
	return 0;
}

那么c++给我们提供了虚继承用来解决这种问题,只需要在son1和son2继承base时使用虚继承即可(grandson正常继承son1和son2),语法:class son1 : virtual public base {}; class son2 : virtual public base {}; 其中base类叫作虚基类,这种继承方式就是虚继承。

class base {
public:
	int m_a;
};

class son1:virtual public base{};
class son2:virtual public base{};
class grandson :public son1, public son2{};

int main()
{
	grandson g;
	g.m_a = 10;//这样这里就不会出现之前的不明确的情况
	return 0;
}

那么为什么加上virtual将能解决上述问题呢,这个就和虚继承的底层实现有关系。


虚继承的底层实现:

在son1和son2虚继承base时,其实继承过来的是一个虚基类指针(vbptr——virtual base pointer),它指向的是一个虚基类表(vbtable——virtual base table),这个表中记录了一个数据——偏移量,当你继承这个虚基类指针时,它通过偏移量也能找到你想要的成员,所以上面的m_a只有一份,grandson中只是继承了两个不同的虚基类指针,通过这两个指针来找到这唯一的m_a,就能解决二义性以及资源浪费问题。

如果大家不是很能理解,也可以打开vs的开发人员命令行提示符来查看类的对象模型。

具体操作步骤如下:

  1. 打开vs的开发人员命令行提示符
  2. 找到你的代码文件所在的盘符并跳转到该盘符
  3. 然后输入cd [代码文件所在的路径]
  4. 跳转到文件所在位置后输入dir
  5. 再输入 cl /d1 reportSingleClassLayout[你想要查看的类名] [ ".cpp文件的名字" ]

接下来可以看看我的对象模型

7f93bad842874bef93b3de5ffbf4036c.png

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

皮城大学生

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

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

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

打赏作者

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

抵扣说明:

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

余额充值