C++类成员内存分布详解

本文将探讨C++类中成员变量的内存分布情况,包括普通成员、静态成员、虚函数等不同情况下的内存布局。


一、基本成员内存布局

1. 普通成员变量

普通成员变量按照声明顺序在内存中连续排列(受访问修饰符和内存对齐影响):

class NormalClass {
public:
    int a;      // 4字节
    char b;     // 4字节(考虑int对齐)
    double c;   // 8字节
    char d;     // 8字节(考虑double 对齐)
};
// sizeof(NormalClass) = 24 (考虑对齐填充)

内存布局:

| 0-3: int a | 4: char b | 5-7: padding | 8-15: double c | 16: char d | 17-23: padding |

2. 带继承的内存布局

派生类的成员追加在基类成员之后:

class Base {
public:
    int base_var; // 4字节
};

class Derived : public Base {
public:
    int derived_var; // 4字节,再加上Base 类的 4字节,总共8字节
};

内存布局:

| 0-3: Base::base_var | 4-7: Derived::derived_var |

二、静态成员的内存分布

静态成员不占用类实例的内存空间,存储在全局数据区

class WithStatic {
public:
    int normal_var;         // 占用实例空间
    static int static_var;  // 不占用实例空间
};
// sizeof(WithStatic) == sizeof(int)

三、虚函数对内存的影响

1. 含有虚函数的类

编译器会隐式添加虚表指针(vptr),通常放在对象起始位置,虚函数表(vtable)本身不占用类实例的内存空间,vtable 存储在程序的只读数据段(全局静态区),每个类(而非对象)共享一个 vtable。虚表指针(vptr)会占用类实例的内存空间,每个对象实例中存储一个指向 vtable 的指针,在 64 位系统中占用 8 字节,32 位系统中占用 4 字节:

class WithVirtual {
public:
    virtual void foo() {}  // 添加vptr
    int a;
};
// 在32位系统上sizeof(WithVirtual) == 8 (vptr + int)
// 在64位系统上sizeof(WithVirtual) == 16 (vptr + int + padding)

内存布局(64位系统):

| 0-7: vptr | 8-11: int a | 12-15: padding |

2. 继承体系中的虚函数

派生类与基类共享同一个vptr(单继承情况下):

class BaseWithVirtual {
public:
    virtual void foo() {}
    int base_var;
};

class DerivedVirtual : public BaseWithVirtual {
public:
    virtual void bar() {}  // 添加到虚表
    int derived_var;
};

内存布局(64位系统):

| 0-7: vptr | 8-11: Base::base_var | 12-15: Derived::derived_var |

四、多继承的内存布局

多继承情况下,每个基类子对象按声明顺序排列:

class Base1 { public: int base1_var; };
class Base2 { public: int base2_var; };

class MultiDerived : public Base1, public Base2 {
public:
    int derived_var;
};

内存布局:

| 0-3: Base1::base1_var | 4-7: Base2::base2_var | 8-11: derived_var |

五、验证内存布局的代码

#include <iostream>
#include <cstddef>

#define PRINT_OFFSET(className, member) \
    std::cout << "Offset of " #member ": " \
    << offsetof(className, member) << std::endl

struct Test {
    virtual void foo() {}  // 添加vptr
    int a;
    char b;
    static int c;
};

int main() {
    std::cout << "Sizeof Test: " << sizeof(Test) << std::endl;
    PRINT_OFFSET(Test, a);  // 64位系统输出 8
    PRINT_OFFSET(Test, b);  // 64位系统输出 12
    return 0;
}

总结表格

特性是否影响实例大小存储位置
普通成员变量栈/堆
静态成员变量全局数据区
虚函数是(添加vptr)虚表
继承追加基类成员
虚继承更复杂布局

注意事项

  1. 实际内存布局可能因编译器实现不同而有所差异
  2. 使用 offsetof 宏验证偏移量
  3. 内存对齐可通过 #pragma pack 指令调整
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值