C++ 虚继承:破解菱形继承的“双亲困境”
1. 菱形继承与虚继承
C++ 是 支持多继承 的语言,允许一个类继承多个基类,该类可以同时拥有多个类的成员函数和成员变量。
多继承的优势在于更高的灵活性(允许构建更复杂的类层次结构),以及更强的代码复用性;同时带来了菱形继承问题。
- 菱形继承问题:当多个基类继承自同一个公共基类时,子类会包含多分基类实例。
D 类会包含两个 A 实例(一个来自 B,一个来自 C),造成二义性。解决方法是 使用虚继承 ,即在派生类继承基类时,使用 virtual 关键字声明基类:
class B : virtual public A {};
class C : virtual public A {};
虚基类 A 由最远派生类 D 构造,D 中只包含一个 A 实例,不再有二义性。
2. 虚继承的实现机制
虚继承的核心在于 虚基类指针 和 虚基类表 。
虚基类指针 vbptr :每个虚继承的 类 都会包含一个隐藏的 vbptr,指向虚基类表;
虚基类表 vbtable :每个虚基类指针(vbptr)指向一个虚基类表。vbtable 存储了一系列偏移量(offset),通过偏移量可以准确定位虚基类的成员变量和函数。
如何观察 vbptr 和 vbtable 呢?
在 MSVC 中,
-
右键项目 -> 属性 -> C/C++ -> 命令行 -> 其他选项
-
添加
/d1reportAllClassLayout
/d1reportAllClassLayout
- 重新编译,输出窗口会显示详细的类内存布局。