本文共 1445 字,大约阅读时间需要 4 分钟。
类的内存模型(二)
1. 单继承关系的对象模型
单继承代码如下:
class Base{ private: int m_Ba; int m_Bb; public: virtual void test();};class Derived : public Base { private: int m_Da; public: virtual void test(); virtual void print();};
对于基类,和之前简单的对象不一样,该对象的内存空间不仅存储非静态的成员变量,而且存储了一个指针,叫“虚指针(vptr)”。只要有虚函数,对象的内存空间就会多出一个虚指针。但注意:无论该对象有多少个虚函数,对象的内存空间也最多只有一个虚指针。
虚指针指向虚表,虚表的每个元素不是函数而是函数指针。
下面是子类的对象的构造过程,即 执行Derived d
-
子类继承父类,所以按照父类构造方式构造(只是按照父类方式,但是还是属于子类对象的内存空间);
-
按照父类方式构造完,新增子类独有的成员变量;
-
新增虚函数(当虚函数与父类虚函数重复时,覆盖虚表中对应的项,即替换函数指针);
-
当子类需要新增虚函数时,需要在虚表中新增一项,存储新的虚函数的函数指针。
以上就是单继承派生类下的内存分布,下面在VS中查看基类Base的内存分布:
然后,再看下单继承类Derived的内存模型:
总结:派生类在继承父类的基本构造方法基础上,也会存储自身的成员变量,继承父类的虚表并在此基础上进行修改。子类的虚函数与父类的虚函数重复时,就讲子类的虚函数指针覆盖到虚表中对应项,对于子类的新的虚函数,会在虚表上新建一项。
2. 多继承下的内存模型
多继承:一个子类有多个父类。
代码如下:
class BaseA{ public: virtual void testA(); private: int m_BA;};class BaseB{ public: virtual void testB(); private: int m_BB;};class Derived : public BaseA, public BaseB { public: virtual void testA(); virtual void testB(); virtual void testD(); private: int m_D;};
转化成UML图之后,如下:
子类内存模型构造如图:
使用VS查看,如下图:
考虑一个问题:菱形继承。用UML表示如下:
使用VS查看内存模型:
问题:Derived的内存空间中有两份m_B,浪费内存空间;其二就是使用时会有歧义。
原因:因为BaseA、BaseB都是继承于Base,所以BaseA、BaseB各有一份m_B,而Derived又是继承于BaseA、BaseB,自然Derived的布局要按照BaseA、BaseB的方式来分布,所以,Derived有两份m_B。
方法1:可以通过指定访问对象来解决
Derived dd;dd.BaseA::m_B = 1;dd.BaseB::m_B = 2;
方法2:要解决空间浪费的问题,就只能使用虛继承来解决。
https://mp.weixin.qq.com/s/pV7lWM5lIKio9b16AW3Rxg
https://mp.weixin.qq.com/s/81vskUmNXYAx6x3FIjl4vA
转载地址:https://blog.csdn.net/qq_45434780/article/details/109967079 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!