虚继承的实现原理_虚继承和普通继承区别

(98) 2024-06-29 11:01:01

为什么要有虚继承?

在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文件的名字" ]

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

虚继承的实现原理_虚继承和普通继承区别 (https://mushiming.com/)  第1张

 

 

THE END

发表回复