0

0

C++ 虚函数表存在哪里 C++对象内存布局详解【进阶】

穿越時空

穿越時空

发布时间:2026-01-26 14:09:09

|

208人浏览过

|

来源于php中文网

原创

vptr是编译器为含虚函数的类对象在内存起始处自动插入的隐藏指针,指向该类型共享的只读vtable,支撑运行时多态;其存在导致memset(this,0,sizeof(*this))等操作会破坏vptr引发崩溃,且多重/虚继承下布局依ABI而异。

c++ 虚函数表存在哪里 c++对象内存布局详解【进阶】

虚函数表指针 vptr 存在对象内存的最开头

每个含虚函数的 C++ 对象,编译器会在其内存布局起始位置(偏移 0)插入一个隐藏指针 vptr,指向该类型的虚函数表(vtable)。这不是你声明的成员,而是编译器自动加的;哪怕类只有一个 virtual 函数,甚至空类继承自虚基类,vptr 都可能出现。

常见错误现象:用 memset(this, 0, sizeof(*this)) 初始化对象,会把 vptr 也清成 0,后续调用虚函数直接崩溃(纯虚函数调用或访问非法地址)。

  • vptr 是运行时多态的基石,没有它,virtual 就退化为普通静态绑定
  • 多重继承下,子类对象可能有多个 vptr(分别对应不同父类子对象),位置依继承顺序和 ABI 而定(如 MSVC 和 Itanium ABI 规则不同)
  • 虚继承时,额外增加虚基类偏移量字段,vptr 仍存在,但虚基类子对象可能不紧邻对象起始

vtable 本身存在全局只读数据段(.rodata.rdata

vtable 是编译期生成的静态数组,存放函数指针和类型信息(如 RTTI 指针、虚基类偏移等),生命周期与程序一致。它不随对象创建/销毁而分配释放,所有同类型对象共享同一份 vtable

使用场景:调试时可通过对象地址反查 vptr,再解引用拿到 vtable 地址,进而查看虚函数地址分布——这对分析多态调用链、定位虚函数覆盖错误很有用。

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

  • Linux 下可用 readelf -x .rodata ./a.out | grep -A10 "vtable" 粗略定位(符号名常被 mangling)
  • MSVC 中调试器可直接展开 “[vtable]” 节点,看到各虚函数地址
  • 修改 vtable 内容(如热补丁)极危险:违反只读段保护,且影响所有该类型对象

虚函数调用如何通过 vptrvtable 定位函数

形如 obj->func() 的虚函数调用,编译器生成的汇编本质是三步:取 vptr → 查 vtable 中对应索引 → 跳转执行。索引由虚函数在类声明中的出现顺序决定(首个虚函数索引为 0),与是否被重写无关。

容易踩的坑:父类新增虚函数会改变整个 vtable 布局,若子类未重新编译,vtable 索引错位,导致调用到错误函数(尤其 DLL / SO 版本不一致时)。

  • 纯虚函数在 vtable 中填的是类似 __cxa_pure_virtual 的占位地址,调用即 abort
  • 析构函数若为虚函数,也会进入 vtable,且通常放在末尾(但标准不保证顺序)
  • 内联虚函数仍进 vtable,只是编译器可能在某些调用点跳过查表直接内联(取决于优化级别)

offsetof 和调试器验证虚函数表布局

不能依赖 offsetof 获取 vptr 偏移(它不是标准成员),但可以用它验证其他成员相对 vptr 的位置。更可靠的方式是用调试器观察实际内存:

class Base { virtual void f() {} };
class Derived : public Base { int x; virtual void g() {} };
Derived d;
// 在 GDB 中:p/x &d     → 对象起始地址
//           p/x *(void**)(&d) → vptr 值(即 vtable 地址)
//           p/x **(void**)(&d) → vtable[0](Base::f 地址)

注意:不同编译器、不同优化等级(-O0 vs -O2)、是否启用 RTTI 都会影响 vtable 内容和对象布局细节。生产环境务必以实际编译产物为准,别套用教科书图示。

虚函数表布局不是语言标准强制规定的,而是 ABI 约定的结果。这意味着跨编译器(比如 GCC 编译的库被 Clang 程序链接)或跨平台(Windows x64 vs ARM64)时,vtable 结构可能不兼容——这是二进制接口稳定性的关键盲区。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

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

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

15

2025.11.27

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

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

15

2025.11.27

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

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

15

2025.11.27

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1073

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

149

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

1172

2025.12.29

java接口相关教程
java接口相关教程

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

14

2026.01.19

windows查看端口占用情况
windows查看端口占用情况

Windows端口可以认为是计算机与外界通讯交流的出入口。逻辑意义上的端口一般是指TCP/IP协议中的端口,端口号的范围从0到65535,比如用于浏览网页服务的80端口,用于FTP服务的21端口等等。怎么查看windows端口占用情况呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

730

2023.07.26

拼多多赚钱的5种方法 拼多多赚钱的5种方法
拼多多赚钱的5种方法 拼多多赚钱的5种方法

在拼多多上赚钱主要可以通过无货源模式一件代发、精细化运营特色店铺、参与官方高流量活动、利用拼团机制社交裂变,以及成为多多进宝推广员这5种方法实现。核心策略在于通过低成本、高效率的供应链管理与营销,利用平台社交电商红利实现盈利。

31

2026.01.26

热门下载

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

精品课程

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

共48课时 | 7.8万人学习

Git 教程
Git 教程

共21课时 | 3万人学习

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

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