如果A继承B和 C,而B和C继承D,则A将D继承了两次。或者A继承B和C,但是B和C中都有一个print函数。
默认情况下,如果某个类在派生过程中出现了多次,则派生类中将包含该类的多个子对象。
虚基类:
为了解决从不同途径继承来的同名的数据成员在内存中有不同的拷贝造成数据不一致问题,将共同基类设置为虚基类。这时从不同的路径继承过来的同名数据成员在内存中就只有一个拷贝,同一个函数名也只有一个映射。这样不仅就解决了二义性问题,也节省了内存,避免了数据不一致的问题。
虚拟继承:
C++使用虚拟继承(Virtual Inheritance),解决从不同途径继承来的同名的数据成员在内存中有不同的拷贝造成数据不一致问题,将共同基类设置为虚基类。这时从不同的路径继承过来的同名数据成员在内存中就只有一个拷贝,同一个函数名也只有一个映射。
#include <iostream> using namespace std; int gFlag = 0; class Base{ public: Base(){ cout << "Base called: " << gFlag++ << endl; } void print(){ cout << "Base print" << endl; } }; class Mid1 :public Base{ public: Mid1(){ cout << "Mid1 called" << endl; } private: }; class Mid2 :public Base{ public: Mid2(){ cout << "Mid2 called" << endl; } private: }; class Child :public Mid1, public Mid2{ public: Child(){ cout << "Child called" << endl; } }; int main(){ Child d; //d.print(); //不能这样使用,会产生二意性 d.Mid1::print(); //只能这样使用 d.Mid2::print(); return 0; }
注意:上面基类构造函数被调用两次
使用虚继承如下:#include <iostream> using namespace std; int gFlag = 0; class Base{ public: Base(){ cout << "Base called: " << gFlag++ << endl; } void print(){ cout << "Base print" << endl; } }; class Mid1 :public Base{ public: Mid1(){ cout << "Mid1 called" << endl; } private: }; class Mid2 :public Base{ public: Mid2(){ cout << "Mid2 called" << endl; } private: }; class Child :public Mid1, public Mid2{ public: Child(){ cout << "Child called" << endl; } }; int main(){ Child d; //d.print(); //不能这样使用,会产生二意性 d.Mid1::print(); //只能这样使用 d.Mid2::print(); return 0; }注意:上面基类构造函数只被调用一次。
#include <iostream> using namespace std; int gFlag = 0; class Base{ public: Base(){ cout << "Base called: " << gFlag++ << endl; } void print(){ cout << "Base print" << endl; } private: int a; }; class Mid1 :virtual public Base{ public: Mid1(){ cout << "Mid1 called" << endl; } private: }; class Mid2 :virtual public Base{ public: Mid2(){ cout << "Mid2 called" << endl; } private: int b; }; class Child :public Mid1, public Mid2{ public: Child(){ cout << "Child called" << endl; } }; int main(){ cout << sizeof(Mid1) << endl; //8 cout << sizeof(Mid2) << endl; //12 cout << sizeof(Child) << endl; //16 return 0; }注意:Child的大小是16字节,因为含有两个虚指针指向两张虚表。