1. 程式人生 > 其它 >[筆記]《Effective C++》第六章 Inheritance and Object-Oriented Design

[筆記]《Effective C++》第六章 Inheritance and Object-Oriented Design

條款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.

  1. derived classes內的名稱會遮掩base classes內的名稱。在public繼承下從來沒有人希望如此。
  2. 為了讓被遮掩的名稱再見天日,可使用using宣告式
    轉交函式(forwarding functions)。

條款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
    模式。tr1::function物件的行為就像一般函式指標。這樣的物件可接納“與給定之目標籤名式(target signature)相容”的所有可呼叫物(callable entities)。
  • 古典的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,儘可能避免在其中放置資料