前面几篇文章,我们介绍了简单对象的内存模型和单继承关系的内存模型。接下来,我们就介绍稍微复杂一点继承关系下的内存模型。这节我们先来看看多重继承,即,一个子类有多个父类。
多重继承的例子
class BaseA
{
public:
virtual void testA();
private:
int m_BA;
};
class BaseB
{
public:
virtual void testB();
private:
int m_BB;
};
class Deliver : public BaseA, public BaseB
{
public:
virtual void testA();
virtual void testB();
virtual void testD();
private:
int m_D;
};
UML类图:
子类内存模型构造过程
1,同样,先按照父类的方式构造内存空间,两个父类,按照继承的顺序,从左至右:
1)按照BaseA的方式构造内存空间
2)按照BaseB的方式构造内存空间
3)基于之前的内存空间再构建属于Deliver独有的成员:
新增Deliver的成员变量:
在第一张虚表中,使用Deliver::testA虚函数的指针覆盖BaseA::testA虚函数的指针:
在第二张表中,使用Deliver::testB虚函数的指针覆盖BaseB::testB虚函数的指针:
在第一张表中新增Deliver::testD()虚函数
使用vs查看内存模型:
菱形继承
再看另外一种情况:
代码:
class Base{public: int m_B;};class BaseA : public Base{public: virtual void testA();private: int m_BA;};class BaseB : public Base{public: virtual void testB();private: int m_BB;};class Deliver : public BaseA, public BaseB{public: virtual void testA(); virtual void testB(); virtual void testD();private: int m_D;};
UML类图:
两个父类共同继承于一个祖父类,整个形状,像菱形一样,俗称菱形继承。
菱形继承带来的问题
使用VS查看内存模型:
问题就是:
1)Deliver的内存空间中有两份m_B,浪费内存空间
2)使用的时候会有歧义
原因是:
由于BaseA、BaseB各自继承于Base,所以,BaseA、BaseB分别有一份m_B,而 Deliver又是继承于BaseA、BaseB,自然Deliver的内存布局是分别按照BaseA、BaseB的方式来分配内存,所以,Deliver有两份m_B。
解决办法:
1)解决使用时候的歧义,可以通过指定访问对象来解决
Deliver dd;dd.BaseA::m_B =1;dd.BaseB::m_B =2;
2)要解决浪费空间的问题,就只能用虚继承来解决
推荐阅读: