当前位置: 首页 > news >正文

C++ 虚继承对象内存布局

C++ 虚继承对象内存布局

一、先区分:普通继承 vs 虚继承

1. 普通公有继承(非虚)

structBase{inta;};structDerived:Base{intb;};

布局:Base部分 + Derived自身成员

Derived 对象内存: [ int a ] // Base [ int b ] // Derived

多继承普通继承会多份基类副本,菱形继承产生二义性,所以引入虚继承 virtual,让所有派生类共享同一份公共基类(虚基类)。

2. 虚继承核心目的

解决菱形继承(钻石继承)的数据冗余、成员二义性问题:公共父类只存一份,派生类通过**虚基表指针(vbase ptr)**间接访问虚基类。

二、核心概念

  1. 虚基类(virtual base class):被virtual继承的上层父类
  2. 虚基表指针(vbptr, virtual base pointer):每个含有虚继承的派生类对象会带一个 vbptr,指向虚基表 vbtable
  3. 虚基表 vbtable:存储「当前对象 → 虚基类子对象」的内存偏移量
  4. 虚基类子对象统一放在派生类内存末尾,所有派生类共享同一份虚基类数据

区分:

  • vptr(虚表指针):虚函数用,存虚函数地址;
  • vbptr(虚基指针):虚继承用,存虚基类偏移。
    一个类可同时有 vptr + vbptr。

三、最简单路虚继承示例

#include<iostream>usingnamespacestd;structVBase{// 虚基类intv_a=10;};structMid:virtualVBase{// 虚继承 VBaseintm_b=20;};

Mid 对象内存布局(32/64位通用逻辑,以64位举例)

Mid包含:

  1. vbptr(虚基指针,8字节64位)
  2. 自身成员m_b(int 4,对齐补4)
  3. 末尾:共享虚基类VBase子对象v_a

内存排布:

Offset 内容 0x00 vbptr → 指向 Mid 的虚基表 vbtable 0x08 m_b (int) 0x0C 填充对齐 4字节 0x10 VBase::v_a (虚基类,放在最后)

Mid 的虚基表 vbtable(vbptr指向这里)

虚基表存储从 vbptr 地址到虚基类子对象首地址的偏移

  • 偏移值:0x10,代表从vbptr位置往后加 0x10 才能找到 VBase。

访问mid.v_a的底层流程:

  1. 取对象首地址,拿到 vbptr;
  2. 查虚基表得到偏移 offset;
  3. 对象首地址 + offset = VBase子对象地址;
  4. 访问v_a

四、经典菱形虚继承(最常考布局)

钻石结构:

Top (虚基类,仅一份) / \ virtual/ \virtual Left Right \ / \ / Down

代码:

structTop{intt=1;};structLeft:virtualTop{intl=2;};structRight:virtualTop{intr=3;};structDown:Left,Right{intd=4;};

Down 对象完整内存布局(64位系统)

规则:

  1. 先放 Left 派生部分:vbptr_Left+ Left::l
  2. 再放 Right 派生部分:vbptr_Right+ Right::r
  3. 再放 Down 自身成员 d
  4. 内存最末尾:唯一一份 Top 虚基类 t
Offset 内容 0x00 vbptr_Left // Left 的虚基指针 0x08 Left::l // int 4 0x0C 对齐填充4 0x10 vbptr_Right // Right 的虚基指针 0x18 Right::r // int4 0x1C 对齐填充4 0x20 Down::d // int4 0x24 对齐填充4 0x28 Top::t // 全局唯一虚基类,所有类共享

两张虚基表

  1. Left 的 vbtable:存 Left 对象首地址到 Top 的偏移0x28
  2. Right 的 vbtable:存 Right 对象首地址到 Top 的偏移0x18
访问逻辑举例:

Down d; d.t;

  • 通过 Left 分支:d首地址 + Left虚基表偏移 → Top地址
  • 通过 Right 分支:d首地址 + Right虚基表偏移 → 同一个Top地址
    完美实现只有一份Top,无冗余、无二义。

五、同时含虚函数 + 虚继承(vptr + vbptr 共存)

structVBase{virtualvoidfunc(){}// 虚函数,带vptrinta;};structDer:virtualVBase{intb;};

Der 对象布局:

  1. vbptr(虚基指针,虚继承用)
  2. Der::b
  3. 末尾:VBase子对象(内含 VBase 的 vptr + int a)
0x00 vbptr 0x08 b 0x10 VBase子对象: 0x10 vptr(虚函数表指针) 0x18 a

区分两个指针:

  • vbptr:属于派生类 Der,用于找虚基类 VBase;
  • vptr:属于虚基类 VBase 内部,用于多态虚函数调用。

六、关键底层规则总结(面试高频)

1. vbptr 生成规则

只要类使用virtual继承任意基类,该类对象就会增加一个vbptr
多虚继承则对应多个 vbptr(菱形中Left、Right各一个)。

2. 虚基类存放固定规则

所有虚基类子对象统一放在派生类内存布局的最后,不会穿插在派生类成员中间。

3. 虚基表 vbtable 存储内容

虚基表里只存偏移量 offset:当前vbptr所在位置 → 虚基类子对象首地址的差值。
不同派生类、不同继承分支,偏移值不同。

4. 大小对比:普通多继承 vs 虚继承

以上面菱形为例:

  • 普通非虚多继承:Down 包含两份Top,内存更大,数据冗余;
  • 虚继承:仅一份Top,代价是每个中间类多一个 vbptr(指针开销)。

5. 构造/析构特殊规则(和布局配套考点)

  1. 虚基类构造最先调用:无论继承层级多深,虚基类构造函数第一个执行;
  2. 只有最底层派生类 Down 能直接初始化虚基类 Top,Left/Right 构造函数对Top的初始化会被忽略;
  3. 析构顺序相反:派生自身 → 中间类 → 虚基类。

七、32位 / 64位系统差异

  • 32位:指针4字节,vbptr/vptr 都是4字节,对齐按4;
  • 64位:指针8字节,对齐按8;
    布局结构逻辑完全一致,仅指针宽度、填充对齐不同。

八、常见面试问题简答

  1. 虚继承为什么能解决菱形二义性?
    虚基类只存一份,派生类通过虚基表偏移间接访问唯一副本,不存在多份数据冲突。
  2. vbptr 和 vptr 区别?
    vptr 对应虚函数表,存函数地址,实现多态;vbptr对应虚基表,存内存偏移,实现共享虚基类。
  3. 虚继承的开销是什么?
    每个含虚继承的子类多一个vbptr,间接访问虚基类成员需要查表计算偏移,性能略低于普通继承。
  4. 虚基类放在对象哪个位置?
    永远在派生类布局末尾,不会在前面。



布局规则,将基类成员变量放到最下面,然后用vbptr代替;
vbptr指向vbtable虚基类表 , 第一行是vbptr相对本身子对象的偏移

http://www.jsqmd.com/news/1119114/

相关文章:

  • 专注核心需求的纯本地音乐播放器
  • Quark-Auto-Save架构设计与自动化转存技术深度解析
  • 4-Hadoop伪分布式搭建基本流程
  • MC0483过园数统计
  • 【干货】基础知识-图像处理
  • 大模型应用中的“中转层”到底解决了什么问题?
  • 西门子S7协议调试工具的技术架构与生产环境下应用
  • 每日文献阅读-复现|2026 npj Computational Materials:130 万候选如何用 AI 与第一性原理筛出 741 种超导体
  • PCB焊盘设计:SMD与NSMD的选择与应用
  • 华为MetaERP Oracle EBS 各模块业务场景与会计分录对照表。由于无法直接生成 Excel 文件,我将以清晰的表格格式呈现,你可以直接复制到 Excel 中使用。Oracle EBS 各
  • 助睿实验指导7:自媒体运营分析三次过程合并-CSDN博客
  • 亲测速度几十MB/s!2026百度网盘不限速下载黑科技,原来大家都偷偷在用
  • 影刀RPA新手教程:邮件自动发送完全指南——从SMTP配置到批量个性化发送
  • (六)海康工业相机与halcon+C#联合编程
  • Claude Code安全审查实战:从SQL注入检测到CI/CD集成指南
  • 92.从底层原理、编程规范、模块化设计到调试避坑!PLC ST 语言工控项目全流程实战
  • 120 万奖金池里,有一块没人抢的肥肉:RWKV-7 × transformers 训练适配
  • RAG落地踩坑实录:从Demo到生产的差距有多大?
  • S1.1 独立产品的变现模式地图:哪种模式最适合你
  • 通过结构化步骤化解社恐压力
  • Dify 实战指南:从零构建企业级 AI 应用与工作流
  • 华为MetaERP Oracle EBS 各模块业务场景及会计分录汇总表文件信息: 共 11个模块 | 300条业务场景 | 编制日期:2026年7月模块目录表格序号 模块名称 业务场景数 主
  • CBC模式密文篡改攻击:无需密钥,直接实现权限提升
  • OpenHarmony Button 按钮组件全场景开发与 API23 + 适配优化
  • 做电子元器件生产的朋友,国内线圈固定胶生产厂家哪家更靠谱?
  • 分享一个连DeepSeek都说“颜值高”的代码截图工具
  • Dify实战指南:一周构建企业级AI应用,从零到精通
  • RAG效果评估:你的知识库到底好不好用?
  • abu_tcp 自定义安全协议源码拆解
  • 一套正版、免费、强大的 Visual Studio 2012 IDE