空类加virtual函数后sizeof不为0,因编译器插入vptr指针(64位占8字节);纯空类sizeof为1以保证对象地址唯一;虚继承引入vbptr,多重虚继承显著增加对象大小;static成员和函数不占对象空间。

空类加 virtual 就不为零了
哪怕一个类只有 virtual 函数、没有数据成员,sizeof 也不会是 0。根本原因是:编译器必须为每个对象安插一个虚函数表指针(vptr),用来支持运行时多态。这个指针本身要占空间——在主流 64 位平台(如 x86_64 上的 GCC/Clang/MSVC)上是 8 字节;32 位平台通常是 4 字节。
比如:
class Base {
public:
virtual void f() {}
};
在 64 位环境下,sizeof(Base) 就是 8,不是 0,也不是 1。
常见错误现象:
- 误以为“没写成员变量 = 没内存” → 忘记
vptr是隐式插入的 - 用
memset(this, 0, sizeof(*this))手动清零对象 → 可能把vptr也清掉了,后续虚函数调用崩溃
为什么空基类也不占 0 字节
即使类完全空着(没函数、没数据、没 virtual),sizeof 仍是 1。这是 C++ 标准强制要求:任何对象在内存中必须有唯一地址,两个空对象不能“叠在一起”。编译器会悄悄塞一个 char 进去占位。
但一旦涉及虚继承或虚函数,这个“占位 char”通常会被优化掉——因为 vptr 或 vbptr 已经提供了唯一地址能力,没必要再额外加 1 字节。
所以这些情况结果不同:
-
struct X {};→sizeof(X) == 1 -
struct Y { virtual void f() {} };→sizeof(Y) == 8(64 位) -
struct Z : virtual X {};→sizeof(Z) == 16(含vptr+vbptr)
多重虚继承让大小跳涨明显
虚继承不只是加一个指针。当多个父类都虚继承同一个基类时,派生类里可能同时存在 vptr(指向虚函数表)和 vbptr(指向虚基类表),每个都是指针大小。
例如:
class Common { int x; };
class A : virtual Common {};
class B : virtual Common {};
class D : public A, public B {};
sizeof(D) 在 64 位下通常是 24:A 的 vptr(8)+ B 的 vptr(8)+ vbptr(8)。注意,Common 的 int x 只存一份,但指针开销是实打实叠加的。
容易踩的坑:
- 以为“虚继承省空间” → 实际可能更费,尤其在深度继承链中
- 跨平台移植时忽略指针宽度差异(32 位 vs 64 位)→
sizeof结果翻倍,序列化或内存映射出错
static 成员和函数完全不占对象空间
只要不是非静态数据成员,就不会计入 sizeof。包括:
-
static数据成员(存在静态区,所有对象共享) - 所有成员函数(代码在 .text 段,不随对象复制)
- 类型定义(
using、enum、嵌套class)
所以这个类:
class Tool {
public:
static int count;
void foo() {}
virtual void bar() {}
using id_t = long;
};
sizeof(Tool) 仍只由 vptr 决定(8 字节),count 和 foo、id_t 都不影响。
真正容易被忽略的是:vptr 插入位置不固定。它可能在对象开头、结尾,甚至中间(受成员布局和对齐影响),调试时用 offsetof 查具体偏移比猜更可靠。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











