对象内存模型

内容简介

C++ 对象中真正占用对象空间的是非静态成员变量。成员函数、静态成员函数和静态成员变量不存放在每个对象内部。

基本规则

  • 非静态成员变量属于对象。
  • 成员函数不属于某个对象的存储空间。
  • 静态成员变量属于类,不属于对象。
  • 空对象也至少占 1 字节,保证不同对象有不同地址。

示例:

class Empty {
};
 
class Person {
public:
    int age;
 
    void func() {}
    static void static_func() {}
    static int count;
};
 
int Person::count = 0;
 
std::cout << sizeof(Empty) << '\n';
std::cout << sizeof(Person) << '\n';

为什么空对象占 1 字节

如果空对象大小是 0,两个不同对象可能有相同地址。C++ 要保证不同对象能被区分,因此空对象至少占 1 字节。

Empty a;
Empty b;
std::cout << (&a == &b) << '\n';  // 通常为 false

成员函数在哪里

成员函数本质上是代码,不为每个对象复制一份。非静态成员函数通过隐藏的 this 指针知道自己操作哪个对象。

class Person {
public:
    void set_age(int age)
    {
        this->age = age;
    }
 
private:
    int age = 0;
};

最佳代码实践

  • 不要以为类里函数多,对象就一定变大。
  • 关注对象大小时,重点看非静态数据成员、对齐和虚函数。
  • 对象是否有虚函数会影响对象布局,通常会引入虚表指针。

错误用法

class Person {
public:
    static int count;
};
 
Person p;
std::cout << sizeof(p) << '\n';  // 不要以为 count 在 p 里面

注意事项

  • 对象布局会受编译器、ABI、对齐规则影响。
  • 多态对象布局更复杂,见 cpp多态
  • 平凡对象、标准布局类型后续可以作为单独主题补充。

学习路径