0
点赞
收藏
分享

微信扫一扫

C++虚继承下的内存模型(二)


对于虚继承,恰恰和普通继承相反,大部分编译器会把基类成员变量放在派生类成员变量的后面,这样随着继承层级的增加,基类成员变量的偏移就会改变,就得通过其他方案来计算偏移量。

下面我们来一步一步地分析虚继承时的对象内存模型。

  1. 修改上面的代码,使得 A 是 B 的虚基类:

#include <iostream>
using namespace std;

class A{
protected:
int m_a1;
int m_a2;
};
class B: virtual public A{
protected:
int b1;
int b2;
};
class C: public B{
protected:
int c1;
int c2;
};
class D: public C{
protected:
int d1;
int d2;
};
int main(){
A obj_a;
B obj_b;
C obj_c;
D obj_d;
return 0;
}

此时 obj_b、obj_c、obj_d 的内存模型就会发生变化,如下图所示:

C++虚继承下的内存模型(二)_c++


不管是虚基类的直接派生类还是间接派生类,虚基类的子对象始终位于派生类对象的最后面。

  1. 再假设 A 是 B 的虚基类,B 又是 C 的虚基类,那么各个对象的内存模型如下图所示:

C++虚继承下的内存模型(二)_虚基类_02


从上面的两张图中可以发现,虚继承时的派生类对象被分成了两部分:

  • 不带阴影的一部分偏移量固定,不会随着继承层次的增加而改变,称为固定部分;
  • 带有阴影的一部分是虚基类的子对象,偏移量会随着继承层次的增加而改变,称为共享部分。

当要访问对象的成员变量时,需要知道对象的首地址和变量的偏移,对象的首地址很好获得,关键是变量的偏移。对于固定部分,偏移是不变的,很好计算;而对于共享部分,偏移会随着继承层次的增加而改变,这就需要设计一种方案,在偏移不断变化的过程中准确地计算偏移。各个编译器正是在设计这一方案时出现了分歧,不同的编译器设计了不同的方案来计算共享部分的偏移。

对于虚继承,将派生类分为固定部分和共享部分,并把共享部分放在最后,几乎所有的编译器都在这一点上达成了共识。主要的分歧就是如何计算共享部分的偏移,可谓是百花齐放,没有统一标准。


举报

相关推荐

0 条评论