繼承與面向對象設計
- 條款 32 - 確定你的 public 塑模出 is-a 關系
- "public繼承" 意味 is-a。適用于 base classes 身上的每一件事情也一定適用于 derived classes 身上,因為每一個 derived classes 對象也都是一個 base classes 對象。
- 條款 33 - 避免遮掩繼承而來的名稱
- derived classes 內的名稱會遮掩 base classes 內的名稱,在 public 繼承下,從未有人希望如此。
- 為了讓遮掩的名稱再見天日,可使用 using 聲明式或轉交函數。
- 條款 34 - 區分接口繼承和實現繼承
- 接口繼承與實現繼承不同,在 public 繼承之下, derived classes 總是繼承 base classes 的接口。
- pure virtual 函數只具體指定接口繼承。
- 簡樸的 impure virtual 函數具體指定接口繼承及缺省實現繼承。
- non-virtual 函數具體指定接口繼承及強制性實現繼承。
- 條款 35 - 考慮 virtual 函數以外的其它選擇
- virtual 函數的替代方案包括 NVI 手法以及 Strategy 設計模式的多種形式,NVI 手法自身是一個特殊形式的 Template Method 設計模式。
- 將機能從成員函數移到 class 外部函數,帶來的一個缺點是非成員函數無法訪問 class 的 non-public 成員。
- tr1::function 對象的行為就像一般函數指針,這樣的對象可接納與給定之目標簽名式兼容的所有可調用物。
- 條款 36 - 決不重新定義繼承而來的 non-virtual 函數
- 絕對不要重新定義繼承而來的 non-virtual 函數
- 條款 37 - 決不重新定義繼承而來的缺省函數參數值
- 絕對不要重新定義一個繼承而來的缺省參數值,因為缺省參數值都是靜態綁定的,而 virtual 函數——你唯一需要復寫的東西——卻是動態綁定的
- 條款 38 - 通過復合塑模出 has-a 或根據某物實現出
- 復合的意義和 public 繼承完全不同
- 在應用域,復合意味 has-a,在實現域,復合意味 is-implemented-in-term-of
- 條款 39 - 明智而審慎地使用 private 繼承
- private 繼承意味 is-implemented-in-terms-of,它通常比復合的級別低,但是當 derived class 需要訪問 protected base class 的成員,或需要重新定義繼承而來的 virtual 函數時,這么設計是合理的。
- 和復合不同,private 繼承可以造成 empty base 最優化,這對致力于 “對象尺寸最小化” 程序庫的開發者而言,可能很重要。
- 條款 40 - 明智而審慎地使用多重繼承
- 多重繼承比單一繼承復雜,它可能導致新的岐義性,以及對 virtual 繼承的需要。
- virtual 繼承會增加大小、速度、初始化復雜度等等成本。如果 virtual base class 不帶任何數據,將是最具實用價值的情況。
- 多重繼承的確有正當用途,其中一個情節涉及 “public 繼承某個 Interface class” 和 “private 繼承某個協助實現的 class” 的兩者相結合。