繼承 (Inheritance)
組合 (composition) 通常比繼承更為適合。 若要使用繼承,請使用
public繼承。
定義
當子類別繼承一個基底類別時,它包含了基底類別所定義的所有資料和操作的定義。 「介面繼承 (interface inheritance)」是指從純抽象基底類別(沒有任何狀態或已定義方法的類別)繼承;其他所有的繼承都屬於「實作繼承 (implementation inheritance)」。
優點
實作繼承透過重複使用基底類別的程式碼來縮減程式碼的大小,同時能夠特化現有的型別。 由於繼承是編譯期的宣告,你和編譯器都能夠理解其操作並偵測錯誤。 介面繼承可以用來以程式化的方式強制一個類別開放特定的 API。 同樣地,編譯器可以在一個類別沒有定義一個 API 中必要的方法時發現問題。
缺點
對於實作繼承來說,由於實作子類別的程式碼分散在基底類別與子類別之間,理解一個實作可能變得更困難。 子類別無法覆寫 (override) 非虛擬 (virtual) 的函式,因此子類別無法更改其實作。
多重繼承 (multiple inheritance) 特別麻煩,因為它通常會帶來更高的效能負擔(事實上,從單一繼承到多重繼承的效能下降幅度,往往大於從普通呼叫切換到虛擬呼叫時的效能下降幅度),而且還有導致「鑽石 (diamond)」繼承模式的風險,這種模式容易引發歧義、困惑以及明顯的錯誤。
決定
所有的繼承都應該是 public。 若要使用私有繼承,你應該改為將基底類別的物件作為成員引入。 當你不打算支援將某個類別用作基底類別時,可以對其標上 final。
不要過度使用實作繼承。 組合通常更為適合。 盡量將繼承的使用限制在「is-a」的情況:如果可以合理地說明「Bar 是某種 Foo」,那麼 Bar 才適合繼承 Foo。
將 protected 的使用限制在那些可能需要從子類別存取的成員函式上。 請注意,資料成員應該是 private。
覆寫虛擬函式或虛擬解構函式時,必須明確地以 override 或 final 其中一個修飾詞(後者較少使用)標註,且不可兩者並用。 在宣告覆寫時不要使用 virtual。 這樣做的理由是:若標有 override 或 final 的函式或解構函式並非基底類別虛擬函式的覆寫,將無法通過編譯,這有助於發現常見的錯誤。 這些修飾詞也具有文件說明的作用;如果沒有標註任何修飾詞,讀者就必須檢查該類別的所有祖先類別,才能判斷該函式或解構函式是否為虛擬的。
多重繼承是被允許的,但強烈不建議多重的實作繼承。