当前位置: 首页 > news >正文

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 指令调整
http://www.dtcms.com/a/121719.html

相关文章:

  • Android 11 (API 30) 及更高版本中,查询的特定应用商店包,无需动态请求权限处理
  • MyBatis 详解及代码示例
  • 机器学习--数据填充
  • 楼宇自控系统构建机电设备管理新方式,提升建筑管理水平
  • 【C++进阶】关联容器:set类型
  • Python 3.x cxfreeze打包exe教程
  • LeetCode 解题思路 35(Hot 100)
  • 如何理解KMP算法中的next数组
  • 气象水文耦合模式 WRF-Hydro 建模技术与案例实践应用
  • [leetcode]差分算法
  • FPGA_DDR错误总结
  • Spring Boot 应用中如何避免常见的 SQL 性能问题
  • C++学习之套接字并发服务器
  • 砍树(二分)
  • 搜广推校招面经七十一
  • 示波器直流耦合与交流耦合:何时使用哪种?
  • Spring Boot 中集成 Knife4j:解决文件上传不显示文件域的问题
  • [漏洞篇]SSRF漏洞详解
  • 华为网路设备学习-17
  • 即时通讯软件BeeWorks,企业如何实现细粒度的权限控制?
  • PostgreSQL-数据库的索引 pg_operator_oid_index 损坏
  • JAVAWeb_Servlet:前置准备与理论简易介绍
  • input_ids ,attention_mask 是什么
  • js解除禁止复制、禁止鼠标右键效果
  • 阿里发布实时数字人项目OmniTalker,实时驱动技术再突破~
  • json 转 txt 用于 yolo 训练(可适用多边形标注框_python)
  • HOW - React Developer Tools 调试器
  • SpringBoot和微服务学习记录Day1
  • 决策树+泰坦尼克号生存案例
  • 强化学习原理一