vptr 是 C++ 编译器为含虚函数的对象自动插入的隐藏指针,位于对象内存布局起始处,大小与平台指针宽度一致(32 位为 4 字节,64 位为 8 字节),指向所属类的虚函数表(vtable);它在构造函数执行前由编译器初始化,单继承下每个对象一个且恒在开头,多重继承时可能有多个。

vptr 是 C++ 编译器为每个含有虚函数的对象自动插入的一个隐藏指针,全称是 virtual function table pointer(虚函数表指针)。它不显式出现在类定义中,但真实存在于对象内存布局的最前端,指向该对象所属类的虚函数表(vtable)。
vptr 的位置和大小
在绝大多数主流编译器(如 MSVC、GCC、Clang)中:
- vptr 位于对象内存布局的起始地址处(即对象首字节),紧随其后才是成员变量;
- 其大小与平台指针宽度一致:32 位系统为 4 字节,64 位系统为 8 字节;
- 可通过
sizeof验证——例如一个仅含一个int和一个虚函数的类,在 64 位 Linux 下对象大小通常为 16 字节(8 字节 vptr + 4 字节 int + 4 字节对齐填充)。
vptr 怎么工作
当通过基类指针或引用调用虚函数时,实际执行流程依赖 vptr:
- 从对象首地址读取 vptr 值(即取出虚函数表起始地址);
- 根据被调用虚函数在类中声明的顺序,计算其在 vtable 中的索引(如第一个虚函数偏移为 0,第二个为 1);
- 用该索引访问 vtable 对应位置的函数指针;
- 间接跳转(
call [rax]类汇编指令)执行目标函数。
这个过程完全在运行时完成,与变量声明类型无关,只取决于对象实际类型。
立即学习“C++免费学习笔记(深入)”;
vptr 不是“每个类一个”,而是“每个对象一个”
注意区分两个概念:
- vtable 是类级别的:每个含虚函数的类有且仅有一个 vtable(存储在只读数据段 .rodata),所有该类对象共享同一张表;
- vptr 是对象级别的:每个对象实例都拥有自己的 vptr 成员,它指向所属类的 vtable —— 派生类对象的 vptr 指向派生类的 vtable,而非基类的。
多重继承时可能有多个 vptr(如虚继承或菱形继承场景),但单继承下始终只有一个,且恒在对象开头。
vptr 的初始化时机
vptr 在对象构造过程中由编译器自动设置:
- 进入构造函数体前,编译器先将当前类的 vtable 地址写入对象首部;
- 若为派生类,构造顺序是:基类构造 → 成员初始化 → 派生类构造体;每一步都会更新 vptr 指向对应阶段的 vtable;
- 因此在基类构造函数中调用虚函数,即使派生类已重写,也只会调用基类版本(此时派生类部分尚未构造,vptr 还指向基类 vtable)。











