继承关系下类的内存布局

参考:https://blog.csdn.net/qq_28114615/article/details/88077009
针对牛客网按知识分类中C++题第158个
1.每一个 class 产生出一堆指向 virtual functions 的指针,放在表格之中,这个表格被称为 virtual table(vtbl)。

2,。每一个 class object 被添加了一个指针,指向相关的 virtual table 。通常这个指针被称为 vptr,在32位系统中占4个字节。64位占8个字节。vptr 的设定(setting)和重置(resetting)都由每一个 class 的constructor、destructor 和 copy assignment 运算符自动完成,每一个 class 所关联的 type_info object (用以支持 runtime type identigication,RTTI)也经由 virtual table 被指出来,通常是放在表格的第一个 slot 处。

从以上信息,我的认识时,一个 class 如果有 virtual function,那么它就会把自己的 virtual function 信息”上交“给 virtual table(vtbl)。如果其他 class 比如 class A 继承它,或者拷贝构造它,那么这个 virtual table 就会被share,A 就会得到该 virtual table 的 vptr,并且如果 A 自己有virtual function,也会产生新的 virtual function 指针放入 vptr 所指的virtual table 之中。然后这个 virtual table 会放在class A 的地址的首部。

### C++ 继承时的内存布局详解 C++ 中的继承会直接影响其对象的内存布局。以下是关于不同情况下继承时内存布局的具体分析。 #### 1. **空内存布局** 即使是一个没有任何成员变量或方法的空,在大多数编译器实现中也会占用至少一个字节的空间,这是为了区分不同的对象实例[^1]。 对于以下定义: ```cpp class B {}; B b; cout << "sizeof(b)=" << sizeof(b) << endl; ``` `b` 的大小通常为 `1` 字节。 #### 2. **虚继承的影响** 当引入虚拟继承时,派生的对象中会包含指向虚基的指针(vptr),用于解决多重继承中的菱形问题。因此,虚继承会使派生的大小增大。 以以下代码为例: ```cpp class B {}; class B1 : public virtual B {}; class B2 : public virtual B {}; class D : public B1, public B2 {}; ``` - 对于 `B1` `B2`,由于它们都通过虚继承自 `B`,所以每个都会有一个指向虚基的指针(vptr)。假设指针大小为 8 字节,则: ```cpp cout << "sizeof(b1)=" << sizeof(B1) << endl; // 输出通常是 8 或更大 cout << "sizeof(b2)=" << sizeof(B2) << endl; // 同理 ``` - 对于 `D`,它同时继承了 `B1` `B2`,而这两个又共同虚继承自 `B`。在这种情况下,`D` 的对象中会有两个 vptr(分别对应 `B1` `B2`)以及一个单独的虚基部分。最终的结果可能是: ```cpp cout << "sizeof(d)=" << sizeof(D) << endl; // 可能是 24 或更大 ``` 具体大小取决于平台编译器实现。 #### 3. **单一继承下的内存布局** 在单一继承且无虚函数的情况下,子会在父的基础上追加自己的成员变量。例如: ```cpp class A { private: int a; }; class B : public A { private: double b; }; ``` 此时,`B` 的对象内存布局将是先存储 `A::a`,再紧接着存储 `B::b`。总大小等于两者之加上可能存在的填充字节[^2]。 #### 4. **带虚函数的单一继承** 如果基中有虚函数,则该及其所有派生都会有虚函数表指针(vptr)。这使得对象大小增加了一个指针的长度。例如: ```cpp class Base { public: virtual void f() {} }; class Derived : public Base { public: int x; }; ``` 在此例子中,`Base` `Derived` 都含有一个 vptr,再加上各自的成员变量。因此: ```cpp cout << "sizeof(Base)=" << sizeof(Base); // 大约为 8 (仅含 vptr) cout << "sizeof(Derived)=" << sizeof(Derived); // 大约为 12 (vptr + int) ``` #### 5. **多继承与复杂情况** 在多继承场景下,尤其是涉及虚继承时,内存布局变得更加复杂。除了普通的成员变量外,还需要额外的空间来管理多个基的关系。例如: ```cpp class Point1D { protected: float x; }; class Point2D : public Point1D { protected: float y; }; class Point3D : public Point2D { protected: float z; }; ``` 在这个简单的线性继承链中,`Point3D` 的内存布局顺序依次为 `x`, `y`, `z`[^3]。但如果加入虚继承或其他复杂的组合关系,则需要更多的元数据支持。 --- ### 总结 C++ 继承时的内存布局受到多种因素影响,包括是否有虚函数、是否使用虚继承以及具体的编译器实现方式等。理解这些机制有助于优化程序性能并避免潜在错误。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值