You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++ 空/非空、虚/非虚类的sizeof内存大小规则答疑

C++类内存占用sizeof测试问题解答

测试背景与代码

我尝试探究不同类型类的内存占用大小,分别测试空类/非空类、含虚函数/不含虚函数类的sizeof取值,测试代码如下:

#include <iostream>

class empty_virtual_base {
    empty_virtual_base() {}
    virtual ~empty_virtual_base() {}
};

class non_empty_virtual_base {
    int a;
    non_empty_virtual_base() {}
    virtual ~non_empty_virtual_base() {}
};

class empty_base {
    empty_base() {}
    ~empty_base() {}
};

class non_empty_base {
    int a;
    non_empty_base() {}
    ~non_empty_base() {}
};

int main() {
    std::cout << "empty virtual class: " << sizeof(empty_virtual_base) << "bytes" << std::endl;
    std::cout << "non empty virtual class: " << sizeof(non_empty_virtual_base) << "bytes" << std::endl;
    std::cout << "empty normal class: " << sizeof(empty_base) << "bytes" << std::endl;
    std::cout << "non empty normal class: " << sizeof(non_empty_base) << "bytes" << std::endl;

    std::cin.get();
    return 0;
}

程序运行输出:

empty virtual class: 4 bytes
non empty virtual class: 8 bytes
empty normal class: 1 bytes
non empty normal class: 4 bytes

已知不含虚函数的空类会分配1字节内存,用于唯一标识类的实例地址,测试中存在两点疑问:

  • 含虚函数的空类大小为4字节,这4字节是指向虚表的vptr指针占用的,为什么这类不需要像普通空类一样额外分配1字节做实例标识?
  • 当类中添加占4字节的int类型成员变量后,含虚函数的类大小为8字节,不含虚函数的类大小为4字节;按之前的认知非虚类应该是1字节占位加4字节int共5字节,为什么原本的1字节占位没有体现?

核心规则说明

要搞懂这两个问题,先记住两个最基础的C++对象内存规则:

  • 所有不同的对象实例,内存地址绝对不能重复。如果一个类没有任何实际存储数据的内容——没有自定义的非静态成员变量、没有虚函数、也没有继承自带成员/虚函数的基类,编译器才会隐式添加1字节的占位,保证声明两个同类对象时地址不冲突。
  • 只要类里已经存在实际占用内存的内容——不管是开发者自己写的成员变量,还是编译器隐式插入的虚表指针vptr,上述的1字节占位就不会被添加。同时类的内存排布需要满足对齐要求,最终总大小必须是类内最大对齐值的整数倍。

疑问解答

为什么带虚函数的空类不需要额外1字节占位?

带虚函数的类,编译器会为每个实例隐式插入一个指向虚函数表的指针vptr,在你测试的32位环境下,指针本身就占4字节。
此时类的实例已经有实打实的4字节内存占用,靠这部分内存已经可以唯一区分不同实例,完全满足地址不重复的要求,自然不需要再多塞1字节占位。如果强行添加这1字节,还会因为指针的4字节对齐要求,额外补3字节填充,平白让类大小涨到8字节,属于完全没必要的内存浪费,编译器不会做这种设计。

为什么加了int成员后,非虚类没有算上1字节占位?

你认知里的「1字节占位+4字节int共5字节」是错误的:那个1字节占位只有在类完全没有任何实际数据成员的时候才会存在。
当你给普通空类添加int类型的非静态成员后,类已经有了4字节的实际数据存储,这部分内存已经足够区分不同实例,那个为了空类准备的1字节占位从一开始就不会被插入,自然不会算入总大小。
而含虚函数的类最终大小为8字节也符合规则:4字节vptr加上4字节int成员,两者的对齐值都是4,加总后刚好是8,满足对齐要求不需要额外填充,因此结果为8字节。

补充:当前测试结果是32位编译环境下的数值,如果切换到64位环境,指针长度为8字节,对应带虚函数的空类大小会是8字节,带int成员的虚类大小会是16字节(8字节vptr + 4字节int + 4字节对齐填充)。


内容的提问来源于stack exchange,提问作者Y. Luo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 14:36:22