C++中类对象所占用的内存空间

一、基本原则

一个 类对象在内存中的大小(sizeof(T))主要由以下因素决定:

  1. 成员变量的大小(内置类型、对象、指针等)。
  2. 对齐填充(padding) —— 为了满足 CPU 内存对齐要求,编译器会在成员之间和末尾加填充字节。
  3. 虚函数表指针(vptr) —— 如果类有虚函数,编译器会在对象中额外存一根指针(通常是 4 或 8 字节)。
  4. 继承 —— 父类成员 + 对齐规则。
  5. 空类特殊规则 —— 空类对象大小至少为 1 字节(保证对象能有唯一地址)。
  6. 类的成员函数不占用类对象的内存空间。

一个类对象的大小 = 所有非静态成员变量大小 + 对齐填充 + 继承带来的子对象大小 + 虚函数表指针开销(如果有)。

二、举例分析

普通类:

  • 每个非静态数据成员都会占用空间。
  • 静态数据成员不属于对象,而是存储在类的静态区,所以不影响对象大小。
class A {
    int x;   // 4字节
    char y;  // 1字节
};

x 需要 4 字节;y 需要 1 字节,但后面会对齐填充 3 字节,使整个对象大小对齐到 4 的倍数;总大小 = 8 字节。

含虚函数:

class B {
    int x;
    virtual void foo() {}
};

x 需要 4 字节;对象里有一个 虚函数表指针 vptr,在 64 位系统下一般是 8 字节。再加上对齐填充,总大小 = 16 字节。

继承:

class Base {
    int a;
};
class Derived : public Base {
    char b;
};

Base 占 4 字节;Derived 增加 1 字节的 b,但是要对齐成 4 的倍数;所以 总大小 = 8 字节。

空类:

class Empty {};

虽然类里啥都没有,但 C++ 要保证不同对象有唯一地址。所以空类对象大小 = 1 字节。

内存对齐:

  • C++ 为了提高内存访问效率,通常会在成员之间插入 padding(填充字节),使得每个成员地址满足其对齐要求。
  • 对象的大小还需要是 最大对齐量的整数倍。
struct B {
    char a;   // 1字节
    int b;    // 4字节
};

内存布局可能是:a (1字节) + 填充 (3字节) + b (4字节) = 总共 8 字节

三、成员变量的地址访问

在 C++ 中:

  • 对象的地址(&obj)指向对象在内存中的起始位置。
  • 成员变量的地址(&obj.member)指向该成员在对象内存布局中的位置。

由于成员变量在对象中是按一定的内存偏移量存放的,所以 成员变量的地址 = 对象的地址 + 偏移量。

示例:

#include <iostream>
using namespace std;

struct A {
    int x;   // 4字节
    char y;  // 1字节(可能有对齐填充)
    double z;
};

int main() {
    A a;

    cout << "对象地址: " << &a << endl;
    cout << "成员 x 地址: " << &a.x << endl;
    cout << "成员 y 地址: " << (void*)&a.y << endl;
    cout << "成员 z 地址: " << &a.z << endl;

    return 0;
}

可能输出(具体依赖编译器和对齐方式):
在这里插入图片描述

四、类的静态成员变量

静态成员变量属于类,而不是对象:静态成员变量在程序的静态存储区(通常是数据段 .data 或 .bss)分配内存。所有对象共享同一份静态变量。因此,它不计入对象的大小。

#include <iostream>
using namespace std;

struct A {
    int x;
    static int s; // 静态成员
};

int A::s = 42; // 必须在类外定义和初始化

int main() {
    A a1, a2;
    cout << "sizeof(A): " << sizeof(A) << endl;
    cout << "&a1: " << &a1 << endl;
    cout << "&a2: " << &a2 << endl;
    cout << "&A::s: " << &A::s << endl;
}

输出结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值