C++中多重继承下的虚表结构

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 类继承了 AB,它有两个虚函数表(分别对应 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() 时:

  1. 编译器知道 paA* 类型;
  2. 假设 A 对象在 C 中偏移为 0,则 pa 本身就是 vptr_A 的位置;
  3. 跟着 vptr_A 指向 vtable_A
  4. 调用第一个槽(slot):C::fa()

执行 pb->fb() 也是同理,只是偏移不一样。


七、相关注意事项

现象/问题 原因
对象有多个 vptr 因为每个虚基类都需要维护自己的虚函数表
强制转换指针可能出错 A* 转为 C* 需调整偏移
多态依然有效 编译器正确处理多个虚表指针

八、总结

项目 单继承 多重继承
虚表数量 1 张 每个有虚函数的父类一张
虚表指针 1 个 vptr 每个父类一个 vptr
内存布局 简单 需要考虑偏移和指针调整
多态支持 简单调用 通过多个 vtable 实现

你可能感兴趣的:(c++,开发语言)