C++怎么理解C++对象模型_C++内存布局与对象构造过程

2次阅读

c++对象模型的核心是内存布局与构造过程:对象内存由成员变量按声明顺序(受对齐影响)排列,含虚函数则含vptr指向vtable;单继承时派生类包含基类子对象及自身成员,vptr指向派生类虚表;多重继承下各基类均有vptr,存在指针调整;虚拟继承通过vbptr确保共享基类唯一;构造时从最基类开始逐层初始化vptr并执行构造函数,析构反之,构造期间虚函数调用不实现动态绑定,因vptr仅指向当前层级虚表。

C++怎么理解C++对象模型_C++内存布局与对象构造过程

理解C++对象模型,关键在于搞清楚内存布局构造过程这两个核心。它不只是语法使用,而是底层如何组织数据、调用函数、支持多态的机制。

内存布局:对象在内存中长什么样?

C++对象的内存布局由其成员变量决定,顺序通常与声明一致,但受内存对齐影响。

  • 非静态成员变量:占据对象的实际空间,按声明顺序排列(编译器可能优化重排)。
  • 静态成员变量:不存储在对象内,属于类的全局区域。
  • 成员函数(非虚):不占对象空间,编译为普通函数,通过隐式this指针访问成员。
  • 虚函数:引入虚函数表(vtable)和虚表指针(vptr)。

例如:

class Base {
public:
   int a;
   virtual void func() {}
   double b;
};

这个对象的内存布局大致是:

立即学习C++免费学习笔记(深入)”;

  • 首先是vptr(指向虚函数表)
  • 然后是int a(4字节
  • 接着是double b(8字节),可能前面有4字节填充以满足对齐

vptr通常放在对象开头,这样即使继承也能统一访问。

单继承中的对象布局

派生类对象包含基类子对象和自己的成员。

class Derived : public Base {
public:
   char c;
   void derivedFunc() {}
};

Derived对象布局:

C++怎么理解C++对象模型_C++内存布局与对象构造过程

AI建筑知识问答

用人工智能ChatGPT帮你解答所有建筑问题

C++怎么理解C++对象模型_C++内存布局与对象构造过程 172

查看详情 C++怎么理解C++对象模型_C++内存布局与对象构造过程

  • vptr(指向Derived的虚表)
  • Base::a
  • Base::b(含填充)
  • Derived::c

虚表中会覆盖Base的func,并记录Derived新增的虚函数地址。

多重继承与虚拟继承

多重继承时,对象包含多个基类子对象,每个带虚函数的基类都有自己的vptr。

  • 对象大小 = 所有基类成员 + 自身成员 + 对齐填充 + 多个vptr
  • 存在“指针调整”问题:Base1* ptr = &derived; 需要调整指针值到对应子对象起始位置

虚拟继承解决菱形继承中的重复基类问题:

  • 共享的基类子对象只存在一份
  • 通过虚基类指针(vbptr)间接访问,增加一层间接性

对象构造过程:一步步建立对象

构造不是一步完成的,而是分阶段进行:

  • 先分配内存(调用operator new)
  • 按继承顺序从最基类开始构造:
    • 构造最顶层基类:初始化其vptr,执行构造函数体
    • 逐层向下,直到派生类
  • 每层构造时,该层的vptr指向当前类的虚表
  • 所有基类构造完后,执行派生类构造函数体

析构则反过来:先执行派生类析构体,再逐层向上析构,每层恢复对应vptr。

关键点:构造期间调用虚函数,不会动态绑定到派生类版本,因为vptr还指向当前构造类的虚表。

基本上就这些。掌握内存布局和构造顺序,才能真正理解C++对象行为背后的逻辑。

text=ZqhQzanResources