《Effective C++》读书笔记 条款40:明智而审慎地使用多重继承
多重繼承的存在有其合理性,但是在使用多重繼承的時候也要注意存在的問題
1.一個派生類可能從多個基類繼承相同的名稱(函數、typedef等等),這會導致較多的歧義
例子:
#include<iostream>using namespace std;class base1 { public:void fun1();void fun2(); };class base2 { public:void fun1();void fun3(); };class Derived :public base1, public base2 {};int main() {Derived d;//d.fun1(); //error C2385 : 對“fun1”的訪問不明確// 可能是“fun1”(位于基“base1”中)// 也可能是“fun1”(位于基“base2”中)return 0; }Derived public繼承自base1和base2,由于兩個基類中存在同名的函數fun1,所以在調用fun1時就出現了歧義,不知道調用的是哪一個,我們可以這樣調用
d.base1::fun1();所以多重繼承可能會導致歧義,就算base的fun1()改為private,也不能阻止這種錯誤。因為C++首先是確認函數的最佳匹配而后才檢驗其可取性。在基類調用時發現兩個相同匹配程度的函數,產生歧義。
2.多重繼承導致菱形繼承問題
如果B,C繼承自A,D又繼承自B,C(都是public繼承),如上圖,
#include<iostream>using namespace std;class A { public:void fun(); private:int b; }; class B:public A { private:int b1;};class C :public A { private:int b2; };class D :public B, public C {};int main() {D d;d.fun(); //error C2385 : 對“fun”的訪問不明確//可能是“fun”(位于基“A”中)// 也可能是“fun”(位于基“A”中)return 0; }運行膽碼會發現調用fun函數產生歧義,錯誤信息是兩個一模一樣的fun位于基A中,原因是這種繼承導致D從B和C中繼承了A,解決辦法就是讓B和C virtual public繼承自A,這雖然可以解決D中存在兩份A的問題。
class B:virtual public A { private:int b1;};class C :virtual public A { private:int b2; };class D :public B, public C {};但是virtual繼承會增加對象的體積,是成員訪問速度變慢等等,并且virtual 基類的初始化由繼承體系中的最底層負責,這里A的初始化由D負責。
盡量不要使用虛基類,如果必須使用,不要在虛基類中放置數據。
多重繼承也有其存在的合理性,用public繼承接口,用private繼承協助實現,這種多重繼承的組合書上寫了一個例子。所以說多重繼承可以使用但是要明智而審慎地使用它
請記住:
1.多重繼承比單一繼承復雜。它可能導致新的歧義性,以及對virtual繼承的需要。
2.virtual繼承會增加大小、速度、初始化(及賦值)復雜度等等成本。如果virtual base classes 不帶任何數據,將是最具有實用價值的情況。
3.多重繼承的確有正當用途。其中一個情節涉及“public繼承某個Interface class”和“private繼承某個協助實現的class”的兩相組合。
總結
以上是生活随笔為你收集整理的《Effective C++》读书笔记 条款40:明智而审慎地使用多重继承的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 华为公司专家组一行莅临物通博联调研指导
- 下一篇: 华为OD机试 - 最短耗时(C++) |