在 C++ 的多重继承 中,虚表(vtable)结构会变得更加复杂。
vptr
),指向对应虚表;vptr
查找虚表中函数地址,实现动态绑定。当一个类从 多个基类继承,而这些基类中都有虚函数时,派生类就需要为每个基类维护一套虚表和 vptr。
#include
using namespace std;
class A {
public:
virtual void fa() { cout << "A::fa()" << endl; }
};
class B {
public:
virtual void fb() { cout << "B::fb()" << endl; }
};
class C : public A, public B {
public:
void fa() override { cout << "C::fa()" << endl; }
void fb() override { cout << "C::fb()" << endl; }
};
C对象内存(简化)
+------------------+
| vptr_A |-----> vtable_A (for A)
+------------------+
| A 子对象成员变量 |
+------------------+
| vptr_B |-----> vtable_B (for B)
+------------------+
| B 子对象成员变量 |
+------------------+
| C 的成员变量 |
+------------------+
vtable_A:
+------------------+
| &C::fa() |
+------------------+
vtable_B:
+------------------+
| &C::fb() |
+------------------+
C
类继承了 A
和 B
,它有两个虚函数表(分别对应 A 和 B);
所以 C
对象中有两个 vptr
:
A
的虚函数;B
的虚函数;调用虚函数时,编译器根据当前指针(例如 A*
或 B*
)决定使用哪个 vptr
和哪张 vtable。
int main() {
C obj;
A* pa = &obj;
B* pb = &obj;
pa->fa(); // 输出 C::fa(),通过 vptr_A 找到 vtable_A 中的 &C::fa
pb->fb(); // 输出 C::fb(),通过 vptr_B 找到 vtable_B 中的 &C::fb
return 0;
}
当你执行 pa->fa()
时:
pa
是 A*
类型;A
对象在 C
中偏移为 0,则 pa
本身就是 vptr_A
的位置;vptr_A
指向 vtable_A
;C::fa()
。执行 pb->fb()
也是同理,只是偏移不一样。
现象/问题 | 原因 |
---|---|
对象有多个 vptr |
因为每个虚基类都需要维护自己的虚函数表 |
强制转换指针可能出错 | 如 A* 转为 C* 需调整偏移 |
多态依然有效 | 编译器正确处理多个虚表指针 |
项目 | 单继承 | 多重继承 |
---|---|---|
虚表数量 | 1 张 | 每个有虚函数的父类一张 |
虚表指针 | 1 个 vptr |
每个父类一个 vptr |
内存布局 | 简单 | 需要考虑偏移和指针调整 |
多态支持 | 简单调用 | 通过多个 vtable 实现 |