千家信息网

c++对象的内存布局是怎样的

发表于:2026-10-31 作者:千家信息网编辑
千家信息网最后更新 2026年10月31日,这篇文章主要讲解了"c++对象的内存布局是怎样的",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"c++对象的内存布局是怎样的"吧!简单非多态的内存布局c
千家信息网最后更新 2026年10月31日c++对象的内存布局是怎样的

这篇文章主要讲解了"c++对象的内存布局是怎样的",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"c++对象的内存布局是怎样的"吧!

简单非多态的内存布局

class X {    int     x;    float   xx;public:    X() {}    ~X() {}    void printInt() {}    void printFloat() {}};
  |                        |                |------------------------| <------ X class object memory layout      |        int X::x        |      |------------------------|  stack segment      |       float X::xx      |       |         |------------------------|       |      |                        |      \|/      |                        |          |                        |------|------------------------|----------------      |         X::X()         |       |------------------------|       |         |        X::~X()         |       |      |------------------------|      \|/      |      X::printInt()     |  text segment      |------------------------|      |     X::printFloat()    |      |------------------------|      |                        |

在本示例中

  • 只有数据成员存储在堆栈中,且其声明顺序或者存储顺序的行为与编译器强相关

  • 所有其他方法(构造函数,析构函数和编译器扩展代码)都进存储在文本段。然后,这些方法将被调用并隐式地在调用对象的第一个参数中传递该指针。

this指针是一个隐含于每一个成员函数中的特殊指针。它是一个指向正在被该成员函数操作的对象,也就是要操作该成员函数的对象。this作用域是在类内部,当对一个对象调用成员函数时,编译程序先将对象的地址赋给this指针,编译器会自动将对象本身的地址作为一个隐含参数传递给函数。也就是说,即使你没有写this指针,编译器在编译的时候也是加上this的,它作为非静态成员函数的隐含形参。被调用的成员函数函数体内所有对类成员的访问,都会被转化为"this->类成员"的方式。

针对第二点,我们类似于:

A x;x.printInt();

其中,X::printInt()这个行为,在编译器中,将处理为

printInt(const X* this)

那么,x.printInt()调用处理将最终成为

printInt(&x);

同时具有虚函数和静态数据成员的内存布局

class X {    int         x;    float       xx;    static int  count;public:    X() {}    virtual ~X() {}    virtual void printAll() {}    void printInt() {}    void printFloat() {}    static void printCount() {}};

其内存布局如下

  |                        |                |------------------------| <------ X class object memory layout      |        int X::x        |stack |------------------------|  |   |       float X::xx      |                        |   |------------------------|      |-------|--------------------------|  |   |         X::_vptr       |------|       |       type_info X        | \|/  |------------------------|              |--------------------------|      |           o            |              |    address of X::~X()    |      |           o            |              |--------------------------|      |           o            |              | address of X::printAll() |      |                        |              |--------------------------|      |                        |------|------------------------|------------      |  static int X::count   |      /|\      |------------------------|       |      |           o            |  data segment                 |           o            |       |      |                        |      \|/------|------------------------|------------      |        X::X()          |       |------------------------|       |         |        X::~X()         |       |      |------------------------|       |       |      X::printAll()     |      \|/       |------------------------|  text segment      |      X::printInt()     |      |------------------------|      |     X::printFloat()    |      |------------------------|      | static X::printCount() |      |------------------------|      |                        |
  • 所有非静态数据成员都按照声明的顺序将空间放入堆栈中,与前面的示例顺序相同。

  • 静态数据成员将空间放入内存的数据段中。使用范围解析运算符(即::)进行的访问。但是在编译之后,就没有像作用域和名称空间那样的东西了。因为,它的名称只是由编译器执行,所以所有内容都由其绝对或相对地址引用。

  • 静态数据成员将空间放入内存的数据段中。使用范围解析运算符(即::)进行的访问。

  • 静态方法进入文本段,并通过作用域解析运算符进行调用。

  • 对于virtual关键字,编译器会自动将指向虚拟表的指针(vptr)插入对象内存表示中。通常,虚拟表是在数据段中为每个类静态创建的,但它也取决于编译器的实现。

  • 在虚拟表中,第一个条目指向type_info对象,该对象包含与当前基类和其他基类的DAG(有向无环图)相关的信息(如果从这些基类派生的信息)。

继承对象的内存布局

class X {    int     x;    string str;public:    X() {}    virtual ~X() {}    virtual void printAll() {}};class Y : public X {    int     y;public:    Y() {}    ~Y() {}    void printAll() {}};

其内存布局信息如下

  |                              |                |------------------------------| <------ Y class object memory layout      |          int X::x            |stack |------------------------------|  |   |              int string::len |  |   |string X::str ----------------|  |   |            char* string::str |          \|/  |------------------------------|      |-------|--------------------------|      |           X::_vptr           |------|       |       type_info Y        |      |------------------------------|              |--------------------------|      |          int Y::y            |              |    address of Y::~Y()    |      |------------------------------|              |--------------------------|      |               o              |              | address of Y::printAll() |      |               o              |              |--------------------------|      |               o              |              ------|------------------------------|--------      |           X::X()             |       |------------------------------|       |         |           X::~X()            |       |      |------------------------------|       |       |         X::printAll()        |      \|/       |------------------------------|  text segment      |           Y::Y()             |      |------------------------------|      |           Y::~Y()            |      |------------------------------|      |         Y::printAll()        |      |------------------------------|      |      string::string()        |      |------------------------------|      |      string::~string()       |      |------------------------------|      |      string::length()        |      |------------------------------|      |               o              |      |               o              |      |               o              |      |                              |
  • 在继承模型中,基类和数据成员类是派生类的子对象。

  • 编译器会在类的构造函数中生成具有所有重写的虚拟功能和为_vptr分配虚拟表的代码的虚拟表。

具有多重继承和虚拟功能的对象的内存布局

class X {public:    int     x;        virtual ~X() {}    virtual void printX() {}};class Y {public:    int     y;        virtual ~Y() {}    virtual void printY() {}};class Z : public X, public Y {public:    int     z;        ~Z() {}    void printX() {}    void printY() {}    void printZ() {}};

内存布局如下

  |                              |                |------------------------------| <------ Z class object memory layoutstack |          int X::x            |           |   |------------------------------|                  |--------------------------|        |   |          X:: _vptr           |----------------->|       type_info Z        |  |   |------------------------------|                  |--------------------------| \|/  |          int Y::y            |                  |    address of Z::~Z()    |      |------------------------------|                  |--------------------------|      |          Y:: _vptr           |------|           |   address of Z::printX() |      |------------------------------|      |           |--------------------------|      |          int Z::z            |      |           |--------GUARD_AREA--------|          |------------------------------|      |           |--------------------------|      |              o               |      |---------->|       type_info Z        |      |              o               |                  |--------------------------|      |              o               |                  |    address of Z::~Z()    |      |                              |                  |--------------------------|------|------------------------------|---------         |   address of Z::printY() |      |           X::~X()            |       |          |--------------------------|        |------------------------------|       |                |          X::printX()         |       |              |------------------------------|       |               |           Y::~Y()            |      \|/              |------------------------------|  text segment      |          Y::printY()         |                      |------------------------------|                      |           Z::~Z()            |                      |------------------------------|                      |          Z::printX()         |                      |------------------------------|                      |          Z::printY()         |                      |------------------------------|                      |          Z::printZ()         |                      |------------------------------|                      |               o              |                      |               o              |                      |                              |

在多继承层次结构中,创建的虚拟表指针(vptr)的确切数目将为N-1,其中N代表类的数目。

如果尝试使用任何基类指针调用Z类的方法,则它将使用相应的虚拟表进行调用。如下例子所示:

Y *y_ptr = new Z;y_ptr->printY(); // OKy_ptr->printZ(); // Not OK, as virtual table of class Y doesn't have address of printZ() method

在上面的代码中,y_ptr将指向完整Z对象内类Y的子对象。

结果,调用任何方法,例如使用y_ptr-> printY()。 使用y_ptr的解析方式如下:

 ( *y_ptr->_vtbl[ 2 ] )( y_ptr )

虚继承内存布局

class X { int x; };class Y : public virtual X { int y; };class Z : public virtual X { int z; };class A : public Y, public Z { int a; };

其布局如下:

  |                |           Y class  ------> |----------------| <------ A class object memory layoutsub-object        |   Y::y         |                            |----------------|             |------------------|                   |   Y::_vptr_Y   |------|      |    offset of X   | // offset(20) starts from Y  Z class  ------> |----------------|      |----> |------------------|     sub-object        |   Z::z         |             |       .....      |                       |----------------|             |------------------|                    |   Z::_vptr_Z   |------|                         |----------------|      |         A sub-object --> |   A::a         |      |      |------------------|                   |----------------|      |      |    offset of X   | // offset(12) starts from Z X class -------> |   X::x         |      |----> |------------------|           shared           |----------------|             |       .....      |            sub-object       |                |             |------------------|
  • 具有一个或多个虚拟基类的派生类的内存表示形式分为两个区域:不变区域和共享区域。

  • 不变区域内的数据与对象的起始位置保持固定的偏移量,而与后续派生无关。

  • 共享区域包含虚拟基类,并且随后续派生和派生顺序而波动。

感谢各位的阅读,以上就是"c++对象的内存布局是怎样的"的内容了,经过本文的学习后,相信大家对c++对象的内存布局是怎样的这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

对象 内存 成员 布局 函数 编译 数据 编译器 指针 静态 区域 方法 顺序 c++ 指向 空间 代码 作用 信息 内容 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 亿人帮互联网科技有限公司 深圳恒合互联网络科技有限公司 互联网科技深圳 科技互联网政务服务 新华互联网科技学院 互联网核心科技是什么 高科技与互联网 未来的互联网科技 时间互联网络科技 湖南洣水互联网科技有限公司扣款 深圳前海聚择互联网科技有限公司 知域互联网科技有限公司大骗子 互联网科技商业 苏州铭阳互联网科技有限公司 洛阳共同富裕互联网科技有限公司 山东有哪些互联网科技公司 互联网硬科技公司 上海同邻互联网科技有限公司规模 万物互联网智能科技 武汉亿视互联网科技有限公司 广西拼得多互联网科技有限公司 互联网实体化科技化 西藏七维空间互联网科技有限公司 福州新华互联网科技学校 知乎 想开互联网科技公司怎么样 合肥互联网科技公司公章图片 梅州GM互联网络科技有限公司 有人说阿里系是互联网科技企业 上海乐五互联网科技有限公司 众联互联网络科技
0