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

简单的面向对象,只有单继承或多继承的情况下,内存模型很好理解,编译器实现起来也容易,C++ 的效率和 C 的效率不相上下。一旦和 virtual 关键字扯上关系,使用到虚继承或虚函数,内存模型就变得混乱起来,各种编译器的实现也不一致,让人抓狂。

这是因为 C++ 标准仅对 C++ 的实现做了框架性的概述,并没有规定细节如何实现,所以不同厂商的编译器在具体实现方案上会有所差异。

本节我们只关注虚继承时的内存模式,有关虚函数的内容将在《C++虚函数详解》一节中讲解。

对于普通继承,基类子对象始终位于派生类对象的前面(也即基类成员变量始终在派生类成员变量的前面),而且不管继承层次有多深,它相对于派生类对象顶部的偏移量是固定的。请看下面的例子:

class A{
protected:
    int m_a1;
    int m_a2;
};
class B: 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_a、obj_b、obj_c、obj_d 的内存模型如下所示:
在这里插入图片描述
A 是最顶层的基类,在派生类 B、C、D 的对象中,A 类子对象始终位于最前面,偏移量是固定的,为 0。b1、b2 是派生类 B 的新增成员变量,它们的偏移量也是固定的,分别为 8 和 12。c1、c2、d1、d2 也是同样的道理。

前面我们说过,编译器在知道对象首地址的情况下,通过计算偏移来存取成员变量。对于普通继承,基类成员变量的偏移是固定的,不会随着继承层级的增加而改变,存取起来非常方便。

posted @ 2022-08-19 22:47  luoganttcc  阅读(58)  评论(0)    收藏  举报