空类sizeof为1,加虚函数后变为8(64位系统),因编译器添加唯一vptr指针;vptr大小固定为指针宽度,不随虚函数数量增加,且虚函数表为类级别共享,vptr为对象级别独有。

会变大,但只加一个指针大小,不是每个虚函数都加。
为什么 sizeof 突然从 1 变成 8(64 位系统)?
空类 class A {} 的 sizeof(A) 是 1 —— 编译器硬塞一个字节,只为保证不同对象有不同地址。一旦加了任意一个 virtual 函数,比如 virtual void f() {},编译器就给每个对象悄悄加一个 vptr(虚表指针),在 64 位系统上占 8 字节,且它总在对象内存最前面。
这个 vptr 不随虚函数数量线性增长:1 个虚函数、5 个虚函数、甚至 20 个,对象大小都只多这 8 字节(64 位)。
- 虚函数表(
vtable)是类级别的,所有该类对象共享一份 -
vptr是对象级别的,每个实例独有一份,指向所属类的vtable - 静态成员、普通成员函数、
inline函数都不影响对象大小
virtual 析构函数也会让对象变大
哪怕类里只有 virtual ~A() = default; 这一行,对象大小照样加 8 字节。因为析构函数是否为 virtual,完全由是否存在 vptr 决定,而不是由“有没有写函数体”决定。
立即学习“C++免费学习笔记(深入)”;
常见误判场景:
- 以为“纯虚析构函数
virtual ~A() = 0;不占空间”——错,它仍要vptr - 以为“没定义析构函数,编译器生成的默认析构函数加
virtual就不加vptr”——错,只要声明了virtual,无论是否显式定义,vptr都存在
继承链中对象大小怎么算?
派生类对象大小 = 基类对象大小 + 派生类新增非静态成员大小 + 内存对齐填充,但 vptr 只加一次。
即使基类和派生类都有虚函数,派生类对象也只有一个 vptr(指向派生类自己的 vtable),不会叠加。
示例:
class Base { virtual void f(); };
class Derived : public Base { virtual void g(); int x; };
假设 int 占 4 字节、64 位系统:
-
sizeof(Base) == 8(仅vptr) -
sizeof(Derived)通常是16:8(vptr) + 4(x) + 4(对齐填充) - 不是
8 + 8 = 16(基类vptr+ 派生类vptr),那是错觉
真正容易被忽略的是:虚函数带来的开销不在“函数数量”,而在“是否启用动态绑定”。哪怕你只用一个 virtual 函数,整个类的对象布局、构造/析构顺序、指针转型行为全都会被 vptr 牵动——它不是可选配件,而是多态机制的锚点。


















