多继承与虚继承内存布局

发布时间:2024年01月03日
class a {int data_a;};
class va : virtual public a {int data_va;};
class va2 : virtual public a {int data_va2;};
class b : public a {int data_b;};
class b2 : public a{int data_b2;};
class child : 
  virtual public va, 
  virtual public b, 
  public va2, 
  public b2 {int data_child;};

内存布局:
1、布局中先实继承类,再子类成员,再虚继承类
2、虚继承的类只实例化一个内存
3、实继承的类,分别实例化一个内存
4、虚继承的类会深度遍历添加虚爷类的内存,且只添加一次,后面用到这个虚爷类时可直接复用
5、子类的虚表与第一个实基类合并,如果没有实基类,则加一个子类的虚表
6、实例化顺序与内存布局不同,是按写的顺序来的,本例中顺序为:va::a() -> va() -> b()::a() -> b() -> va2() -> b2::a() -> b2() 其中va2的构造不需要再调一次a的构造,因为虚类只有一个。

/** 实继承虚基类 */
*vtbl_va2 
data_va2
// 这里没有va2::a 的 data_a 因为是虚继承的a类
// 虚类a只有一个,它会在深度遍历virtual继承类va时添加在va后面。
/** 实继承实基类 */
*vtbl_b2 
b2::a::data_a // b2实继承的a,所以先有a的成员再有b2的成员
data_b2
// 子类成员
data_child
/** 虚继承虚基类 */
*vtbl_va
data_va
// 虚继承深度遍历找到虚基基类a,放在这后面
*vtbl_a
data_a
/** 虚继承实基类 */
*vtbl_b
b::a::data_a
data_b

虚表的特点:
1、虚表位置-16为本基类相对子类(无论父还是爷,都是相对子类)的this指针偏移。
2、虚表位置-8指向子类(无论父还是爷,都是其子类)的typeinfo所在位置(即typeid(class)的返回地址)。
3、子类会修改所有基类(以及爷类)的虚表中重写了的虚函数的指针。
4、子类的虚表与第一个实继承类的虚表合并,没有实继承类时,单独创建一个虚表在最顶部。

文章来源:https://blog.csdn.net/qq_37517281/article/details/135365378
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。