C++ 虚函数表(vtable)深度解析 发布时间:2026/11/1 6:26:31 1. 引言在 C 的面向对象编程中多态Polymorphism是三大核心特性之一而虚函数表Virtual Table简称 vtable正是 C 实现动态多态的底层机制。很多初学者在使用virtual关键字时只知道「加了 virtual 就能实现多态」却不清楚编译器究竟在背后做了什么。本文将带你深入 C 虚函数表的内部实现从内存布局、对象模型到多重继承下的复杂情况一步步揭开 vtable 的神秘面纱。2. 什么是虚函数表虚函数表是编译器为每个包含虚函数的类生成的一张函数指针数组表中按声明顺序存放该类所有虚函数的地址。每个含有虚函数的对象其内存开头会多出一个虚函数表指针vptr指向所属类的虚函数表。当通过基类指针或引用调用虚函数时程序会先取出对象的 vptr再根据虚函数在表中的偏移量找到实际要调用的函数地址从而实现「运行时绑定」。classBase{public:virtualvoidfunc1(){std::coutBase::func1std::endl;}virtualvoidfunc2(){std::coutBase::func2std::endl;}voidnonVirtual(){}// 非虚函数不进虚函数表};上述Base类的虚函数表大致如下偏移内容0Base::func1()1Base::func2()3. 对象内存布局一个含有虚函数的对象其内存布局通常为------------------ | vptr8 字节 | -- 指向虚函数表 ------------------ | 成员变量 | ------------------vptr 由编译器在构造函数中自动初始化指向当前类的虚函数表。因此对象的大小会比「仅成员变量」多出一个指针的大小64 位平台下为 8 字节。classBase{public:virtualvoidfunc(){}intx;// 4 字节};// sizeof(Base) 在 64 位平台通常为 16vptr 8 字节 对齐后的 x 8 字节4. 虚函数调用过程通过基类指针调用虚函数时编译器生成的代码大致等价于Base*pnewDerived();p-func();// 编译后等价于// (*(p-vptr[0]))(p);即先取对象的 vptr再按虚函数在表中的下标取出函数指针并调用。这个过程称为动态绑定也是多态得以实现的根本原因。5. 继承与虚函数表5.1 单继承当派生类继承基类并重写虚函数时派生类的虚函数表中对应槽位会被替换为派生类自己的函数地址未重写的虚函数则沿用基类的地址。classDerived:publicBase{public:voidfunc1()override{std::coutDerived::func1std::endl;}// func2 未重写沿用 Base::func2};Derived的虚函数表偏移内容0Derived::func1()1Base::func2()5.2 派生类新增虚函数如果派生类新增了虚函数这些新函数会追加到虚函数表的末尾classDerived:publicBase{public:voidfunc1()override{}virtualvoidfunc3(){}// 新增虚函数};Derived的虚函数表偏移内容0Derived::func1()1Base::func2()2Derived::func3()6. 多重继承下的虚函数表多重继承是虚函数表最复杂的场景。派生类继承多个基类时会拥有多个 vptr分别指向各基类子对象的虚函数表。classBase1{public:virtualvoidf1(){}};classBase2{public:virtualvoidf2(){}};classDerived:publicBase1,publicBase2{public:voidf1()override{}voidf2()override{}};Derived对象的内存布局------------------ | vptr1指向 Base1 的虚函数表 | ------------------ | Base1 成员 | ------------------ | vptr2指向 Base2 的虚函数表 | ------------------ | Base2 成员 | ------------------ | Derived 成员 | ------------------当通过Base2*调用f2()时编译器会先对指针做偏移调整使其指向Derived对象中的Base2子对象再通过 vptr2 找到函数地址。7. 虚继承与虚基类表虚继承virtual继承用于解决菱形继承中的二义性问题。虚继承的类会额外维护一个虚基类表指针vbptr指向虚基类表vbtable表中记录了虚基类子对象相对于当前对象的偏移量。classA{public:virtualvoidfa(){}};classB:virtualpublicA{};classC:virtualpublicA{};classD:publicB,publicC{};在D的对象中A的子对象只有一份B和C通过各自的 vbptr 找到共享的A子对象。这使得虚继承的对象布局更加复杂也带来一定的运行时开销。8. 虚函数表的常见问题8.1 构造函数中调用虚函数在构造函数中调用虚函数不会触发动态绑定而是调用当前类自身的版本。因为构造时 vptr 指向的是当前正在构造的类的虚函数表子类尚未构造完成。classBase{public:Base(){func();}// 调用 Base::func而非 Derived::funcvirtualvoidfunc(){std::coutBase::funcstd::endl;}};8.2 析构函数应声明为虚函数当通过基类指针删除派生类对象时若析构函数非虚则只会调用基类的析构函数导致派生类资源泄漏。因此基类的析构函数应声明为 virtual。8.3 虚函数表的性能开销虚函数调用比普通函数调用多一次间接寻址通过 vptr 查表在性能敏感场景如高频循环中可能成为瓶颈。但现代 CPU 的分支预测和缓存机制通常能有效缓解这一开销。9. 总结虚函数表是编译器为含虚函数的类生成的函数指针数组对象通过 vptr 指向它。单继承下派生类重写虚函数会替换表中对应槽位新增虚函数追加到表尾。多重继承下对象拥有多个 vptr分别对应各基类子对象。虚继承额外引入 vbptr用于定位共享的虚基类子对象。构造函数中调用虚函数不会动态绑定基类析构函数应声明为虚函数。理解虚函数表是深入理解 C 对象模型、多态机制乃至性能优化的关键一步。希望本文能帮你彻底搞懂 vtable 的来龙去脉。 相关新闻 送礼的顶级分寸:不刻意、不施压、刚刚好 慢慢经历人情世故才彻底懂得,送礼的最高境界,从来不是奢华昂贵,也不是排场盛大,而是让人舒服的分寸感。所有长久的情谊,所有体面的往来,靠的从来不是重金堆砌,而是恰到好处的温柔与得体。很多人… 2026/11/1 6:26:36 全流程学术创作效率实测——基于6个月科研实操数据 一、评测前言 在高校科研与学术创作场景中,效率低、规范乱、创新难是制约硕博研究生、青年科研工作者的三大核心痛点。传统学术写作模式下,文献调研、框架搭建、内容撰写、格式排版、查重合规等环节需依托多款工具配合,人工成本高、流程繁琐… 2026/11/1 6:26:37 无人值守配电站房动环监控与智能联动解决方案! 配电站房是城市配电网的末端节点,直接面向用户供电。随着配电自动化和无人值守模式的推广,配电站房的运维方式正在从"定期人工巡检"向"远程集中监控智能联动"转变。配电站房的典型特征:空间相对紧凑,设备密度… 2026/11/1 6:26:37 最新新闻 1.c++入门篇 1.c中的关键字asmdoifreturntrycontinueautodoubleinlineshorttypedefforbooldynamic_castintsignedtypeidpublicbreakelselongsizeoftypenamethrowcaseenummutablestaticunionwchar_tcatchexplicitnamespacestatic_castunsigneddefaultcharexportnewstructusingfriendclassext… 2026/11/1 2:02:05 《江灯合声》:有可行的分框版,也仍可以选择连续鸣谢 武汉江岸区栎坡合唱团在免费节目册《江灯合声》中,以表格集中鸣谢资助者。各家共同要求改为独立小框,团里仍想保留表格。现有全名与支持事项清楚可见,双方此前未承诺具体排版。我支持保留表格。补充的试排材料让选择更具体:分框能… 2026/11/1 2:02:05 关于“贾子猜想”的数学地位、结构特征与讨论边界 关于“贾子猜想”的数学地位、结构特征与讨论边界摘要 本文对“贾子猜想”进行基于公开表述与现有数学事实的分析。该猜想主张:当正整数 n3m>5(即 n6,9,12,15,…)时,方程x₁ⁿ x₂ⁿ ⋯ xₙⁿ yⁿ不存在正整数解。文章首先… 2026/11/1 2:02:05 启动报Port 8088 was already in use?先查是谁占的 启动报Port 8088 was already in use?先查是谁占的 项目启动报 Port 8088 was already in use,意思很直白:这个端口已经有人占了。 先说原理:端口是"门牌号",一间房只住一个进程 端口就是一台机器上的门牌号… 2026/11/1 2:02:05 担心文档上云?本地运行的办公AI才敢放心用 单位上周开了个会,主题是"AI 提效",散会时领导补了一句:涉及客户资料的文档,不许往云端传。这话一出,会议室里本来跃跃欲试的同事全蔫了——大家平时用的那些在线 AI,文档一上传就不知道存哪儿去… 2026/11/1 2:02:04 zk使用--api讲解 1.zookeeper_init ZOOAPI zhandle_t *zookeeper_init(const char *host, // 服务器地址列表(可含 chroot)watcher_fn fn, // 全局 watcher 回调int recv_timeout, // 期望的会话超时(毫秒)const cl… 2026/11/1 1:59:04 日新闻 DRV8818+MK20DX128步进电机驱动方案:从电路到固件实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … 2026/11/1 1:02:01 DRV8818PWPR+PIC18LF46K40双极步进电机驱动实战指南 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … 2026/11/1 1:02:01 DRV8818PWPR与MK20DX128VFM5工业级双极步进控制协同设计 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … 2026/11/1 1:02:01 周新闻 DRV8818+MK20DX128步进电机驱动方案:从电路到固件实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … 2026/11/1 1:02:01 DRV8818PWPR+PIC18LF46K40双极步进电机驱动实战指南 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … 2026/11/1 1:02:01 DRV8818PWPR与MK20DX128VFM5工业级双极步进控制协同设计 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … 2026/11/1 1:02:01 月新闻 DRV8818+MK20DX128步进电机驱动方案:从电路到固件实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … 2026/11/1 1:02:01 DRV8818PWPR+PIC18LF46K40双极步进电机驱动实战指南 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … 2026/11/1 1:02:01 DRV8818PWPR与MK20DX128VFM5工业级双极步进控制协同设计 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … 2026/11/1 1:02:01
送礼的顶级分寸:不刻意、不施压、刚刚好 慢慢经历人情世故才彻底懂得,送礼的最高境界,从来不是奢华昂贵,也不是排场盛大,而是让人舒服的分寸感。所有长久的情谊,所有体面的往来,靠的从来不是重金堆砌,而是恰到好处的温柔与得体。很多人… 2026/11/1 6:26:36
全流程学术创作效率实测——基于6个月科研实操数据 一、评测前言 在高校科研与学术创作场景中,效率低、规范乱、创新难是制约硕博研究生、青年科研工作者的三大核心痛点。传统学术写作模式下,文献调研、框架搭建、内容撰写、格式排版、查重合规等环节需依托多款工具配合,人工成本高、流程繁琐… 2026/11/1 6:26:37
无人值守配电站房动环监控与智能联动解决方案! 配电站房是城市配电网的末端节点,直接面向用户供电。随着配电自动化和无人值守模式的推广,配电站房的运维方式正在从"定期人工巡检"向"远程集中监控智能联动"转变。配电站房的典型特征:空间相对紧凑,设备密度… 2026/11/1 6:26:37
1.c++入门篇 1.c中的关键字asmdoifreturntrycontinueautodoubleinlineshorttypedefforbooldynamic_castintsignedtypeidpublicbreakelselongsizeoftypenamethrowcaseenummutablestaticunionwchar_tcatchexplicitnamespacestatic_castunsigneddefaultcharexportnewstructusingfriendclassext… 2026/11/1 2:02:05
《江灯合声》:有可行的分框版,也仍可以选择连续鸣谢 武汉江岸区栎坡合唱团在免费节目册《江灯合声》中,以表格集中鸣谢资助者。各家共同要求改为独立小框,团里仍想保留表格。现有全名与支持事项清楚可见,双方此前未承诺具体排版。我支持保留表格。补充的试排材料让选择更具体:分框能… 2026/11/1 2:02:05
关于“贾子猜想”的数学地位、结构特征与讨论边界 关于“贾子猜想”的数学地位、结构特征与讨论边界摘要 本文对“贾子猜想”进行基于公开表述与现有数学事实的分析。该猜想主张:当正整数 n3m>5(即 n6,9,12,15,…)时,方程x₁ⁿ x₂ⁿ ⋯ xₙⁿ yⁿ不存在正整数解。文章首先… 2026/11/1 2:02:05
启动报Port 8088 was already in use?先查是谁占的 启动报Port 8088 was already in use?先查是谁占的 项目启动报 Port 8088 was already in use,意思很直白:这个端口已经有人占了。 先说原理:端口是"门牌号",一间房只住一个进程 端口就是一台机器上的门牌号… 2026/11/1 2:02:05
担心文档上云?本地运行的办公AI才敢放心用 单位上周开了个会,主题是"AI 提效",散会时领导补了一句:涉及客户资料的文档,不许往云端传。这话一出,会议室里本来跃跃欲试的同事全蔫了——大家平时用的那些在线 AI,文档一上传就不知道存哪儿去… 2026/11/1 2:02:04
zk使用--api讲解 1.zookeeper_init ZOOAPI zhandle_t *zookeeper_init(const char *host, // 服务器地址列表(可含 chroot)watcher_fn fn, // 全局 watcher 回调int recv_timeout, // 期望的会话超时(毫秒)const cl… 2026/11/1 1:59:04
DRV8818+MK20DX128步进电机驱动方案:从电路到固件实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … 2026/11/1 1:02:01
DRV8818PWPR+PIC18LF46K40双极步进电机驱动实战指南 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … 2026/11/1 1:02:01
DRV8818PWPR与MK20DX128VFM5工业级双极步进控制协同设计 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … 2026/11/1 1:02:01
DRV8818+MK20DX128步进电机驱动方案:从电路到固件实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … 2026/11/1 1:02:01
DRV8818PWPR+PIC18LF46K40双极步进电机驱动实战指南 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … 2026/11/1 1:02:01
DRV8818PWPR与MK20DX128VFM5工业级双极步进控制协同设计 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … 2026/11/1 1:02:01
DRV8818+MK20DX128步进电机驱动方案:从电路到固件实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … 2026/11/1 1:02:01
DRV8818PWPR+PIC18LF46K40双极步进电机驱动实战指南 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … 2026/11/1 1:02:01
DRV8818PWPR与MK20DX128VFM5工业级双极步进控制协同设计 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … 2026/11/1 1:02:01