MST

星途 面试题库

面试题:C++ 虚基类对内存布局的影响

详细阐述 C++ 虚基类是如何影响对象的内存布局的?在多重继承和虚继承结合的场景下,内存布局又有哪些特点?
13.9万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

虚基类对对象内存布局的影响

  1. 单一虚继承场景
    • 在单一虚继承中,当一个类虚继承自另一个类(虚基类)时,派生类对象的内存布局会发生变化。派生类对象中会包含一个指向虚基类子对象的指针(通常称为虚基表指针,vbtptr)。
    • 例如,假设有类Base作为虚基类,类Derived虚继承自Base
class Base {
public:
    int baseData;
};

class Derived : virtual public Base {
public:
    int derivedData;
};
  • 在这种情况下,Derived对象的内存布局大致为:先存储vbtptr,然后是derivedDatavbtptr指向一个虚基表,虚基表中记录了Base子对象相对于Derived对象起始地址的偏移量。这样,通过vbtptr和虚基表,Derived对象可以找到其虚基类Base子对象的位置。
  1. 优点
    • 这种布局方式的主要优点是,无论有多少个派生类通过虚继承继承自同一个虚基类,虚基类子对象在内存中只会存在一份,避免了多重继承中可能出现的基类子对象重复问题。

多重继承和虚继承结合场景下的内存布局特点

  1. 内存布局结构
    • 当存在多重继承且部分基类是虚继承时,情况会更加复杂。假设类Base1Base2是虚基类,类Derived多重继承自Base1Base2,同时还从非虚基类Base3继承:
class Base1 {
public:
    int base1Data;
};

class Base2 {
public:
    int base2Data;
};

class Base3 {
public:
    int base3Data;
};

class Derived : virtual public Base1, virtual public Base2, public Base3 {
public:
    int derivedData;
};
  • Derived对象的内存布局通常为:首先是Base1对应的虚基表指针(vbtptr1),接着是Base2对应的虚基表指针(vbtptr2),然后是Base3子对象(按照非虚继承的方式直接嵌入),再之后是derivedData。每个虚基表指针指向对应的虚基表,虚基表记录了相应虚基类子对象相对于Derived对象起始地址的偏移量。
  1. 避免重复子对象
    • 这种布局确保了Base1Base2的子对象在Derived对象中只存在一份,即使有多个派生路径可以到达它们。如果没有虚继承,在多重继承场景下,可能会出现Base1Base2子对象的重复,导致内存浪费和命名冲突等问题。
  2. 访问虚基类成员
    • 编译器会利用虚基表指针和虚基表来计算虚基类子对象的地址,以便正确访问虚基类的成员。例如,当访问Derived对象中的Base1成员时,会通过vbtptr1找到对应的虚基表,再根据虚基表中的偏移量定位到Base1子对象,从而访问其成员base1Data