[筆記]《Effective C++》第六章 Inheritance and Object-Oriented Design
阿新 • • 發佈:2021-09-22
條款32:Make sure public inheritance models"is-a."
“public繼承”意味is-a。適用於base classes身上的每一件事情一定也適用於derived classes身上,因為每一個derived class物件也都是一個base class物件。
必須牢記:
- public inheritance(公開繼承)意味 "is-a"(是一種)的關係。
條款33:Avoid hiding inherited names.
- derived classes內的名稱會遮掩base classes內的名稱。在public繼承下從來沒有人希望如此。
- 為了讓被遮掩的名稱再見天日,可使用using宣告式
條款34:Differentiate between inheritance of interface and inheritance of implementation.
- public繼承下,成員函式的介面總是會被繼承。
- 宣告一個pure virtual函式的目的是為了讓derived classes只繼承函式介面。
- 我們可以為pure virtual函式提供定義,呼叫它的唯一途徑是“呼叫時明確指出其class名稱”。
- 宣告簡樸的(非純)impure virtual函式的目的,是讓derived classes繼承該函式的介面和預設實現
- 宣告non-virtual函式的目的是為了令derived classes繼承函式的介面及一份強制性實現。
- 一個non-virtual成員函式所表現的不變性(invariant)凌駕其特異性(specialization),所以它絕不該在derived class中被重新定義。
條款35:Consider alternatives to virtual functions.
可以採用以下方法作為虛擬函式的替代:
- 藉由Non-Virtual Interface手法實現Template Method模式。
- 藉由Function Pointers實現Strategy模式。
- 藉由tr1::function(C++11中已經加入標準庫)完成Strategy
- 古典的Strategy模式。將繼承體系內的 virtual函式替換為另一個繼承體系內的virtual函式。
條款36:Never redefine an inherited non-virtual function.
任何情況下都不該重新定義一個繼承而來的non-virtual函式。
條款37:Never redefine a function's inherited default parameter value.
virtual函式系動態繫結(dynamically bound),而預設引數值卻是靜態繫結(statically bound)。
- 物件的所謂靜態型別(static type),就是它在程式中被宣告時所採用的型別。
- 物件的所謂動態型別(dynamic type)則是指“目前所指物件的型別”。
條款38:Model "has-a" or "is-implemented-in-terms-of" through composition.
- 複合意味has-a(有一個)或is-implemented-in-terms-of (根據某物實現出)。
- 當複合發生於應用域內的物件之間,表現出has-a的關係;當它發生於實現域內則是表現is-implemented-in-terms-of的關係。
- 程式中的物件其實相當於你所塑造的世界中的某些事物,例如人、汽車、一張張視訊畫面等等。這樣的物件屬於應用域(application domain)部分。
- 其他物件則純粹是實現細節上的人工製品,像是緩衝區(buffers)、互斥器(mutexes)、查詢樹(search trees)等等。這些物件相當於你的軟體的實現域(implementation domain)。
條款39:Use private inheritance judiciously.
1 Private繼承意味is-implemented-in-terms of(根據某物實現出)。它通常比複合(composition)的級別低。但是當derived class需要訪問protected base class的成員,或需要重新定義繼承而來的virtual函式時,這麼設計是合理的。
2 和複合(composition)不同,private繼承可以造成empty base最優化(EBO)。這對致力於“物件尺寸最小化”的程式庫開發者而言,可能很重要。
- 如果classes之間的繼承關係是private,編譯器不會自動將一個derived class物件(例如Student)轉換為一個base class物件(例如Person)。
- 由private base class繼承而來的所有成員,在derived class中都會變成private屬性,縱使它們在base class中原本是protected或public屬性。
- private繼承意味只有實現部分被繼承,介面部分應略去。
- 儘可能使用複合,必要時才使用private繼承。
條款40:Use multiple inheritance judiciously.
1 多重繼承比單一繼承複雜。它可能導致新的歧義性,以及對virtual繼承的需要。
2 virtual繼承會增加大小、速度、初始化(及賦值)複雜度等等成本。如果virtual base classes不帶任何資料,將是最具實用價值的情況。
3 多重繼承的確有正當用途。其中一個情節涉及“public繼承某個Interface class”和“private繼承某個協助實現的class”的兩相組合。
對virtual base classes(亦相當於對virtual繼承)的忠告:
- 第一,非必要不使用virtual bases。平常請使用non-virtual繼承。
- 第二,如果你必須使用virtual base classes,儘可能避免在其中放置資料。