空类对象必须占至少1字节,因编译器需保证同一数组中不同元素地址唯一;若为0则违反C++标准,故插入匿名char占位;空基类优化(EBO)可在继承时消除该开销,但仅限无虚函数、无虚继承的空基类。

空类对象必须占至少 1 字节,否则无法区分不同实例
为什么 sizeof(Empty) 返回 1 而不是 0
编译器强制要求每个对象在内存中拥有唯一地址。如果 sizeof(Empty) 是 0,那么多个 Empty 对象(比如数组 Empty arr[2])就会被挤在同一地址,&arr[0] == &arr[1] 成立——这违反了 C++ 标准中“同一数组内不同元素地址必须不同”的规定。
因此,哪怕类里一个成员都没有,编译器也会悄悄塞入一个匿名的 char 或等效占位符,让 sizeof 至少为 1。
空基类优化(EBO)能消除这部分开销吗
可以,但仅限于作为基类时被继承,且该基类本身不含虚函数、不参与虚继承。
立即学习“C++免费学习笔记(深入)”;
- 若
class Derived : public Empty { int x; };,多数编译器会把Empty的“占位字节”和x合并布局,sizeof(Derived)可能等于sizeof(int) - 但若
Empty声明了虚函数,它就必须带虚表指针(vptr),此时sizeof(Empty)至少为指针大小(如 8 字节 on x64) - EBO 不适用于成员变量:
struct S { Empty e; int x; };中e仍会占据 1 字节(可能被对齐填充放大)
常见误判场景:结构体 vs 类、模板参数包终止
很多人看到 struct {}; 在 C++ 中合法,就以为它“真没开销”,但:
- C 语言不允许空结构体,
struct {} s;在纯 C 下非法;C++ 允许,但语义上仍需满足对象唯一性 - 空类常用于模板元编程中作类型标记或递归终止条件(如参数包展开),这时它的“存在感”只在类型系统里,运行时虽占 1 字节,但通常不造成实际负担
- 若用空类做
std::vector<Empty>的元素,每个元素仍占 1 字节 + 分配器额外开销,别指望它“零成本”
真正影响 size 的不是“空”,而是“有没有虚函数或虚继承”
决定一个类对象大小的关键不是它有没有数据成员,而是:
- 是否存在虚函数 → 引入 vptr(通常 8 字节)
- 是否虚继承 → 可能引入额外虚基类指针
- 成员变量的类型与顺序 → 决定对齐填充量
- 是否被其他类继承 → 触发 EBO 或禁用 EBO(如多重继承含同名空基类)
所以别盯着 class Empty {}; 看,先查它是不是带 virtual,再看它在哪被用——单独一个空类对象占 1 字节是铁律,但嵌入复杂继承链后,它的空间贡献可能彻底消失。这也是最容易被忽略的点:你以为删掉一个空基类能省 1 字节,其实它早被 EBO 吃掉了;你以为加个空类无害,结果它带了虚函数,直接让整个派生类胖一圈。


















