c++虚表的内存结构
创建:2025-04-19 21:37
更新:2025-04-24 22:44

单继承的虚表布局

  1. 基类结构
    包含虚函数的类首地址存储vptr,指向虚函数表(vtable)。表中按声明顺序存储所有虚函数的地址。
  2. 派生类行为
  • 覆盖虚函数:直接替换基类虚函数表中对应位置的函数指针。
  • 新增虚函数:在基类虚函数表末尾追加新条目,不会新增vptr(单继承仅保留一个vptr)。
  • 内存布局:派生类对象起始位置为基类子对象,之后是派生类成员。
// 示例:资料6中的虚表扩展逻辑
Base* obj = new Derived();
// obj->vptr 指向的虚表结构:[Base::func1, Derived::func2, Derived::func3]

多继承的虚表布局

  1. 多基类情况
    派生类会为每个含有虚函数的基类生成独立的vptr,按继承顺序排列在对象头部。
  2. this指针调整
    调用不同基类的虚函数时,需通过虚表中的偏移量调整this指针(如资料1中d2_ptr->show()需调整this-0x10)。
  3. 派生类新增虚函数
    通常追加到第一个基类的虚表末尾,其他基类的虚表不受影响。

虚继承的内存布局

  1. 虚基类特性
    虚基类的子对象在派生类中仅保留一份,位于对象尾部,通过虚基表指针(vbptr) 定位。
  2. 内存结构
  • 派生类包含:非虚基类的vptr、自身成员、虚基类子对象。
  • 虚基表存储虚基类子对象的偏移量,解决菱形继承的二义性。
// 资料1中的虚继承示例
class Derived2 : virtual public Base { /*...*/ };
// 内存布局:[Derived2的vptr, 成员变量, vbptr, Base子对象]

关键修正与标准引用

  1. vptr数量规则
  • 单继承:仅一个vptr,无论新增多少虚函数。
  • 多继承:每个含虚函数的基类对应一个vptr。
  • 用户原观点修正:自身新增虚函数不会新增vptr,而是扩展现有虚表。
  1. 动态类型转换
    dynamic_cast依赖虚表中的RTTI信息,通过调整this指针实现跨继承层级的转换(如资料2的dynamic_cast<void*>(b))。

总结

继承类型 vptr数量 虚表扩展逻辑 内存调整关键点
单继承 1个(基类vptr) 追加新虚函数到基类虚表末尾 无this指针调整
多继承 每个基类1个vptr 新虚函数追加到第一个基类虚表 需跨基类调整this指针
虚继承 基类vptr+vbptr 虚基类偏移量通过虚基表管理 解决菱形继承冗余