0x01 菱形继承ios
假设有类B和类C,它们都继承了相同的类A。另外还有类D,类D经过多重继承机制继承了类B和类C。函数
若是直接继承会引起访问不明确(二义性),以及数据冗余。若是直接指定访问对象,可解决二义性,而要解决数据冗余,则要引入虚函数。spa
由于图表的形状相似于菱形(或者钻石),所以这个问题被形象地称为菱形问题(钻石继承问题)。对象
示例代码:blog
#include <Windows.h> #include <iostream> using namespace std; class Life { public: Life() :LifeMeaning(5) { } public: int LifeMeaning; }; class Bird :public Life { public: Bird() :BirdMeaning(0x50) { } public: int BirdMeaning; }; class Human :public Life { public: Human() :HumanMeaning(0x100) { } public: int HumanMeaning; }; class Angel :public Bird, public Human { public: Angel() :AngelMeaning(0x30) { } public: int AngelMeaning; }; int main() { Angel Angel; return 0; }
内存窗口观察Angel对象的基地址,能够看到有两个05(Life中的成员变量LifeMeaning的值05),这是由于子类对象会包父类的成员变量。对于Bird和Human来讲,都会去包含Life类中LifeMeaning的值05。对于天使Angel来讲,会同时包含Bird和Human的全部成员。故而LifeMeaning的这个变量在子类Angel中出现了两次,这是菱形继承问题。继承
对于二义性,能够经过做用域符指定访问对象来消除(Angel.Bird::LifeMeaning),而数据冗余的问题,则要经过虚继承。内存
0x02 虚继承作用域
实例代码:io
#include <Windows.h> #include <iostream> using namespace std; class Life { public: Life() :LifeMeaning(0x5) { } public: int LifeMeaning; }; class LifePropagate1 :virtual public Life { public: LifePropagate1() :LifePropagate1Meaning(0x50) { } public: int LifePropagate1Meaning; }; class LifePropagate2 :virtual public Life { public: LifePropagate2() :m_B(0x60) { } public: int m_B; }; class NewLife :public LifePropagate1, public LifePropagate2 { public: NewLife() :NewLifeMeaning(0x100) { } public: int NewLifeMeaning; }; int main() { NewLife NewLifeObject; return 0; }
内存窗口观察NewLifeObject对象的基地址:class
LifePropagate1与LifePropagate2 共用一个虚基类。最终虚基类的数据只有一份,数据冗余和二义性问题再也不。
那么,虚继承又是怎么解决这些烦人的问题的呢?
能够看到在B和C中再也不保存Life中的内容,保存了一份偏移地址,而后将最原始父类的数据保存在一个公共位置处这样保证了数据冗余性的下降同时,也消除了二义性。