在派生類中對基類成員訪問應該是唯一的,但是在多繼承時,可能會導致對基類某成員訪問出現不一致的情況,這就是C++多繼承中的二義性。
有兩種繼承的情況會產生多義性
一、如果一個派生類從多個基類派生,而這些基類又有一個共同的基類,則在對該基類中聲明的成員變量進行訪問時,可能產生二義性,繼承關係如下圖所示:
#includeusing namespace std; class A{ public: int a; }; class B1 : public A{ public: int b1; }; class B2 : public A{ public: int b2; }; class C : public B1, public B2{ public: int c; }; int main(){ C c1; c1.b1 = 100; c1.b2 = 200; c1.c = 300; c1.a = 500; //報錯,不能確定成員變量a具體在那個類 cout << "end..." << endl; system("pause"); return 0; }
解決方法:虛繼承
注意:C++編譯系統在實例化C類時,只會將虛基類A的構造函數調用一次,忽略虛基類的其他派生類(class B1,class B2)對虛繼承的構造函數的調用,從而保證了虛基類的數據成員不會被多次初始化。
在虛基類A中有一個虛指針指向一個虛表,虛表中記錄了虛基類與本類的地址偏移,通過這個地址偏移可以找到虛基類的成員變量a的地址
#includeusing namespace std; class A{ public: int a; }; class B1 : virtual public A{ public: int b1; }; class B2 : virtual public A{ public: int b2; }; class C : public B1, public B2{ public: int c1; }; int main(){ C c1; c1.b1 = 100; c1.b2 = 200; c1.c1 = 300; c1.a = 500; //虛繼承使得成員變量a只有一份拷貝,通過虛指針可以確定地址 cout << "end..." << endl; system("pause"); return 0; }
二、一個派生類同時繼承兩個基類,這兩個基類存在相同的成員函數
#includeusing namespace std; class Base1 { public: void fun() { cout << "I am base-1 " << endl; }; }; class Base2 { public: void fun() { cout << "I am base-2 " << endl; }; }; class A: public Base1, public Base2 { public: void print() { } }; int main() { A obj; obj.fun(); //調用的方法產生歧義 system("pause"); return 0; }
解決方法:使用作用域運算符::來解決,明確指向的方法,例如obj.Base1::fun()
[zhang3221994 ] C++多重繼承二義性原理實例解析已經有462次圍觀