C++单一、多重继承下的内存模型
一:C++单一继承下的内存模型:
a)、最简单的一种单一继承内存模型:基类及派生类中无virtual function member:
#include <iostream> class Base { public: Base(char _x = '\0') :m_x(_x) {} ~Base() {} private: char m_x; }; class Derived :public Base { public: Derived(char _x = '\0',int _y = 0,int _s = 0) :Base(_x), m_y(_y),m_z(_s) {} ~Derived() {} private: int m_y; int m_z; }; int main() { Derived d('A',20,30); return 0; }
在MSVC2015 Debug ×86下,&d = 0x00eff88c;&d.m_x = 0x00eff88c;&d.m_y = 0x00eff890;&d.m_z = ;至于d.m_x为什么会占用4个字节空间大小,这个跟内存对齐有关,由此可见,在单一继承下且类中non-virtual function member时,在派生类中内存模型:地址由低到高,分别为:派生类对象中基类子对象数据成员地址(顺序由基类中数据成员申明先后有关)、派生类特有对象数据成员地址(同上);
b)、单一继承下有virtual function member情况下:
#include <iostream> class Base { public: Base(char _x = '\0') :m_x(_x) {} virtual void Show() { std::cout<<"this is BaseClass"<<std::endl; } ~Base() {} private: char m_x; }; class Derived :public Base { public: Derived(char _x = '\0',int _y = 0,int _s = 0) :Base(_x), m_y(_y),m_z(_s) { } virtual void Show() { std::cout << "this is Derived" << std::endl; } ~Derived() {} private: int m_y; int m_z; }; int main() { Derived d('A',20,30); return 0; }
同样是在上述环境下,取&d = 0x0133f730;&d.m_x = 0x00133f734;&d.m_y = 0x00133f738;&d.m_z = 0x00133f73c;发现&d!=&d.m_x,这是由于在这四个字节的内存空间当中,存放了指向virtual function table(此为一列表格(可将其理解为数组),此表格中存放的是类中virtual function地址,vptr指向第一个在类中申明的virtual地址)的地址vptr;由此可以看到,在单继承模型中,派生类对象的内存模型:地址由低到高,分别为:vptr所指向的地址,派生类对象中基类子对象数据成员地址(顺序由基类中数据成员申明先后有关)、派生类特有对象数据成员地址(同上);
二:C++多重继承下的内存模型:
这也是C++与其他Object-Oriented编程语言如:java,C#的一个很大的不同,在java和C#当中取消了多重继承,取而代之的是通过继承接口的方式实现一种多继承;
#include <iostream> class Base1 { public: Base1(char _x = '\0') :m_x(_x) {} virtual void Show() { std::cout<<"this is Base1Class"<<std::endl; } ~Base1() {} private: char m_x; }; class Base2 { public: Base2(int _a = 0):m_a(_a) {} virtual void display() { std::cout << "this is Base2Class" << std::endl; } private: int m_a; }; class Derived :public Base1,Base2 { public: Derived(char _x = '\0',int _a = 0,int _y = 0,int _s = 0) :Base1(_x), Base2(_a),m_y(_y),m_z(_s) { } virtual void Show() { std::cout << "this is Derived inherited by Base1" << std::endl; } virtual void display() { std::cout << "this is Dervied inherited by Base2" << std::endl; } ~Derived() {} private: int m_y; int m_z; }; int main() { Derived d('A',10,20,30); return 0; }
内存地址分布如下:
此时可以看到,在派生类对象模型中,地址由低到高,分别为:在继承申明时,派生类中第一个基类子对象的vptr,派生类中第一个基类子对象的地址;派生类中第二个基类子对象的vptr,派生类中第二个基类子对象的地址....由此进行类推;
总结:从上述分析可知,在派生类对象的内存模型当中,地址从低到高,分别为:基类当中vptr所指向的地址-->派生类中基类子对象地址-->派生类vptr所指向的地址-->派生类中特有对象的地址:
值得一提的是在发生类似于菱形继承时,通过virtual 继承方式,对象的内存模型会更加复杂;