C++ 类对象所占用的空间

基本原则
  1. 成员函数不占类对象的内存空间:成员函数的代码存储在代码段中,所有对象共享这段代码。
  2. 一个类对象至少占1个字节内存空间:即使一个类没有成员变量,编译器也会分配至少1个字节的空间。
  3. 成员变量是包含在每个对象中的,占用字节:每个对象的成员变量在对象中独立存在。
  4. 成员函数与类对象的关系:成员函数定义在类中,但成员函数不占用类对象的内存。成员函数与类关联,与对象无关,不论创建多少个对象,成员函数的代码只存储一份。
静态成员与虚函数
  1. 静态成员变量不计算在对象的 sizeof:静态成员变量属于类本身,而不是类的对象。
  2. 普通成员函数和静态成员函数不计算在 sizeof:它们与类对象的内存占用无关。
  3. 虚函数增加对象的内存大小:虚函数表指针(vptr)需要额外的内存,通常是8字节(在64位系统上)。
  4. 虚函数表基于类存在:虚函数表(vtable)是类级别的,而不是对象级别的。
内存对齐和填充字节
  1. 内存对齐

    • 为了访问速度和性能,编译器可能会在成员变量之间插入填充字节。举例:
    class Example {
        char a;  // 1字节
        int b;   // 4字节
    };
    
    • 为了对齐,char a可能会被填充为4字节,所以对象大小是8字节而不是5字节。
  2. 指针的大小:指针类型的大小在64位系统上是8字节,在32位系统上是4字节。

对象大小的组成
  1. 非静态成员变量所占的内存总量:包括这些成员变量之间内存字节对齐所额外占用的内存。
  2. 虚函数表指针(vptr)
    • 当一个类包含虚函数时,每个该类的对象都会有一个指向虚函数表(vtable)的指针,称为vptr
    • 不论该类定义了多少个虚函数,所有对象只会占用一个vptr的内存大小。
  3. 构造函数和析构函数的影响
    • 虽然构造函数和析构函数本身不直接影响对象的内存大小,但它们的存在可能会影响虚函数表的生成,尤其是在使用虚函数时。
  4. 继承的影响
    • 如果一个类从另一个类继承,子类的大小不仅包括自己的成员变量,还包括父类的成员变量。此外,如果父类有虚函数,子类也会包含一个指向虚函数表的指针。
  5. 内存布局的优化
    • 通过合理的成员变量顺序来减少填充字节。例如,将相同类型的成员变量放在一起,可能会减少内存占用。
示例验证

可以通过实际代码和sizeof操作符来验证:

// 以下注释是基于64位系统
#include <iostream>

class MyClass1 {
public:
    int a; // 4字节
    void func() { a = 10; } // 不占用对象内存
};

class MyClass2 {
public:
    static int b; // 不占用对象内存
    static void func() { b = 10; } // 不占用对象内存
};

int MyClass2::b = 0;

class MyClass3 {
public:
    virtual void func() {} // 有虚函数,增加vptr
    int a; // 4字节
};

class Base {
public:
    virtual void func() {} // 有虚函数,增加vptr
    int x; // 4字节
};

class Derived : public Base {
public:
    double y; // 8字节
};

int main() {
    std::cout << "Size of MyClass1: " << sizeof(MyClass1) << " bytes" << std::endl; // 应为 4
    std::cout << "Size of MyClass2: " << sizeof(MyClass2) << " bytes" << std::endl; // 应为 1
    std::cout << "Size of MyClass3: " << sizeof(MyClass3) << " bytes" << std::endl; // 应为 16 (8 + 4 + 4)
    std::cout << "Size of Base: " << sizeof(Base) << " bytes" << std::endl; // 应为 16 (8 + 4 + 4)
    std::cout << "Size of Derived: " << sizeof(Derived) << " bytes" << std::endl; // 应为 24 (8 + 8 + 4 + 4)
    return 0;
}

运行以上代码可以验证上述总结的正确性和实际效果。

总结

理解C++类对象的内存占用涉及多个因素,包括成员变量、内存对齐、虚函数表指针等。通过掌握这些原则,可以更好地设计和优化类的内存布局,从而提高程序的性能和效率。

  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值