0

0

c++的虚函数表(vtable)是如何工作的? (深入理解多态)

裘德小鎮的故事

裘德小鎮的故事

发布时间:2026-01-11 12:35:33

|

708人浏览过

|

来源于php中文网

原创

虚函数表指针(vptr)始终位于对象内存起始处,指向编译期生成的虚函数表(vtable);vtable按虚函数声明顺序存储函数指针,构造/析构中vptr动态更新以保障正确多态调用。

c++的虚函数表(vtable)是如何工作的? (深入理解多态)

虚函数表指针(vptr)在对象内存布局中的位置

每个含有虚函数的类,编译器会在其对象的最开始处隐式插入一个 vptr(虚函数表指针),指向该类的虚函数表(vtable)。这个指针大小取决于平台(通常是 8 字节在 64 位系统上),且**永远位于对象内存的起始地址**。

这意味着:sizeof 一个含虚函数的类,一定 ≥ 指针大小;即使类中只有虚函数、无成员变量,sizeof 也不为 0。

  • 派生类对象也包含自己的 vptr,但若未重写基类虚函数,则对应表项仍指向基类实现
  • 多重继承时,子对象可能有多个 vptr(例如每个虚基类子对象一份),布局更复杂,但主流编译器(如 GCC、MSVC)通常只在最派生对象开头放一个主 vptr,其余通过偏移调整
  • 注意:vptr 是编译器自动维护的,无法在 C++ 源码中直接访问或修改;尝试用 reinterpret_cast 强转取址属于未定义行为

虚函数表(vtable)的内容与生成时机

vtable 是编译期生成的静态数组,每个类(而非每个对象)一份,存储的是函数指针(void (*)() 类型),按虚函数声明顺序排列。纯虚函数在表中存为 nullptr 或特定陷阱地址(如 GCC 填 __cxa_pure_virtual)。

关键点:

立即学习C++免费学习笔记(深入)”;

  • 构造函数中,对象的 vptr 会被逐步设置:先设为基类 vtable 地址,进入派生类构造函数后才更新为派生类 vtable
  • 因此,在基类构造函数里调用虚函数,实际执行的是基类版本——哪怕派生类已重写,此时 vptr 还没被改写
  • 析构同理:析构顺序与构造相反,vptr 逐层回退,确保调用对应层级的虚函数

多态调用如何通过 vtable 实现(以 g++ 为例)

当通过基类指针或引用调用虚函数时,CPU 执行流程是:取对象首地址 → 解引用 vptr 得到 vtable 起始地址 → 按虚函数在类中声明顺序计算偏移(如第 0 个是 func1,则取 vtable[0])→ 调用该地址处的函数

DeepL
DeepL

DeepL是一款强大的在线AI翻译工具,可以翻译31种不同语言的文本,并可以处理PDF、Word、PowerPoint等文档文件

下载

示例代码可验证这一机制:

#include 
struct Base {
    virtual void f() { std::cout << "Base::f\n"; }
    virtual void g() { std::cout << "Base::g\n"; }
};
struct Derived : Base {
    void f() override { std::cout << "Derived::f\n"; }
};
int main() {
    Derived d;
    // 强制读取 vptr(仅用于演示,非标准做法)
    void** vptr = *static_cast(&d);
    std::cout << "vtable addr: " << vptr << "\n";
    // 调用 vtable[0](即 f())
    using Func = void(*)();
    Func f_ptr = reinterpret_cast(vptr[0]);
    f_ptr(); // 输出 "Derived::f"
}

注意:reinterpret_cast 访问 vtable 是非便携、非标准行为,仅用于教学观察;实际项目中绝不应依赖此方式。

虚函数调用的性能开销与优化边界

相比普通函数调用,虚函数多一次内存加载(从对象取 vptr)+ 一次间接跳转(查 vtable + call),现代 CPU 的分支预测器通常能很好处理这种规律性跳转,所以开销极小(通常就几个周期)。

但以下情况会破坏可预测性,导致性能下降:

  • 热路径中频繁切换不同子类对象(vtable 地址变化大,vptr 加载后缓存局部性差)
  • 虚函数内联失败:编译器无法在编译期确定目标函数,故不内联(除非启用 LTO + 全局分析)
  • 启用了控制流完整性(CFI)等安全机制时,间接调用需额外验证,开销上升

真正影响性能的往往不是 vtable 查找本身,而是虚函数常伴随动态内存分配、缓存不友好访问模式等副作用。别过早优化 vtable,先确认它真是瓶颈。

相关专题

更多
java多态详细介绍
java多态详细介绍

本专题整合了java多态相关内容,阅读专题下面的文章了解更多详细内容。

15

2025.11.27

javascriptvoid(o)怎么解决
javascriptvoid(o)怎么解决

javascriptvoid(o)的解决办法:1、检查语法错误;2、确保正确的执行环境;3、检查其他代码的冲突;4、使用事件委托;5、使用其他绑定方式;6、检查外部资源等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

175

2023.11.23

java中void的含义
java中void的含义

本专题整合了Java中void的相关内容,阅读专题下面的文章了解更多详细内容。

97

2025.11.27

Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

63

2026.01.14

php与html混编教程大全
php与html混编教程大全

本专题整合了php和html混编相关教程,阅读专题下面的文章了解更多详细内容。

31

2026.01.13

PHP 高性能
PHP 高性能

本专题整合了PHP高性能相关教程大全,阅读专题下面的文章了解更多详细内容。

73

2026.01.13

MySQL数据库报错常见问题及解决方法大全
MySQL数据库报错常见问题及解决方法大全

本专题整合了MySQL数据库报错常见问题及解决方法,阅读专题下面的文章了解更多详细内容。

20

2026.01.13

PHP 文件上传
PHP 文件上传

本专题整合了PHP实现文件上传相关教程,阅读专题下面的文章了解更多详细内容。

24

2026.01.13

PHP缓存策略教程大全
PHP缓存策略教程大全

本专题整合了PHP缓存相关教程,阅读专题下面的文章了解更多详细内容。

7

2026.01.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
CSS3 教程
CSS3 教程

共18课时 | 4.5万人学习

Sass 教程
Sass 教程

共14课时 | 0.8万人学习

Pandas 教程
Pandas 教程

共15课时 | 0.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号