读书笔记《Effective C++》条款40:明智而审慎地使用多重继承
一旦涉及多重繼承,C++社群便分為兩個基本陣營。一派認為如果單一繼承是好的,多重繼承一定更好。另一派主張,單一繼承是好的,但多重繼承不值得使用。
最先需要認清的一件事是,當用到多重繼承,程序有可能從一個以上的base class繼承相同名稱(如函數、typedef等等),那會導致較多的歧義。例如:
class BorrowableItem { public:void checkOut(); };class ElectronGadget { private:bool checkOut() const; };class MP3Player : public BorrowableItem, public ElectronGadget {};MP3Player mp; mp.checkOut();//歧義:調用的是哪個checkOut? 注意此例中對checkOut的調用是有歧義的,即使兩個函數之中只有一個可取用(BorrowableItem內的checkOut是public,ElectronicGadget內的卻是private)。這與C++用來解析重載函數調用的規則相符:在看到是否有個函數可取用之前,C++首先確認這個函數對此調用之言是最佳匹配。找出最佳匹配函數后才檢驗其可取性。本例中的兩個checkOut函數有相同的匹配程度,沒有所謂最佳匹配。因此ElectronicGadget::checkOut的可取用性也就從未被編譯器審查。為了解決這個歧義,必須明確指出要調用哪一個base class內的函數:
mp.BorrowableItem::checkOut();多重繼承的意思是繼承一個以上的base class,但這些base class并不常在繼承體系中又有更高級的base class,那會導致要命的“鉆石型多重繼承”:
class File {}; class InputFile : public File {}; class OutputFile : public File {}; class IOFile : public InputFile, public OutputFile {};任何時候如果有一個繼承體系而其中某個base class和某個derived class之間有一條以上的相同路線,就必須面對這樣一個問題:是否打算讓base class內的成員變量經由每一條路徑被復制?假設File class有個成員變量fileName,那么IOFile內該有多少筆這個名稱的數據呢?從某個角度說,IOFile從其每一個base class繼承一份,所以其對象內應該有兩份fileName成員變量。但從另一個角度說,IOFile對象只該有一個文件名稱,所以它繼承自兩個base class而來的fileName不該重復。C++對這兩個方案都支持——雖然其缺省做法是執行復制。如果那不是你想要的,你必須令那個帶有此數據的class(也就是File class)成為一個virtual base class。為了這樣做,必須令所有直接繼承自它的class采用“virtual繼承”:
class File {}; class InputFile : virtual public File {}; class OutputFile : virtual public File {}; class IOFile : public InputFile, public OutputFile {};從正確行為的觀點看,public繼承應該總是virtual。但是為了避免繼承得來的成員變量重復,編譯器必須提供若干幕后工作,而其后果是:使用virtual繼承的那些class所產生的對象往往比使用non-virtual繼承的class體積大,訪問virtual base class的成員變量時,也比訪問non-virtual base class的成員變量速度慢。種種細節因編譯器不同而異,但基本重點很清楚:你得為virtual繼承付出代價。
virtual繼承的成本還包括其他方面。支配“virtual base class初始化”的規則比其non-virtual base的情況遠為復雜且不直觀。virtual base的初始化責任是有繼承體系中的最低層class負責。
忠告很簡單:第一,非必要不使用virtual base。平常請使用non-virtual繼承。第二,如果你必須使用virtual base class,盡可能避免在其中放置數據。這么一來就不需要擔心這些class身上的初始化(和賦值)所帶來的詭異事情了。Java和.Net的Interface值得注意,它在許多方面兼容于C++的virtual base class,而且也不允許含有任何數據。
要點:
1.多重繼承比單一繼承復雜。它可能導致新的歧義性,以及對virtual繼承的需要。
2.virtual繼承會增加大小、速度、初始化(及賦值)復雜度等等成本。如果virtual base class不帶任何數組,將是最具實用價值的情況。
3.多重繼承的確有正當用途。其中一個情節涉及“public繼承某個interface class”和“private繼承某個協助實現的class”的兩相組合。
總結
以上是生活随笔為你收集整理的读书笔记《Effective C++》条款40:明智而审慎地使用多重继承的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 李宏毅 机器学习 2016 秋:5、Cl
- 下一篇: LuceneElasticSeach