精華區beta C_and_CPP 關於我們 聯絡資訊
※ 引述《pziyout (pziyout)》之銘言: : ※ 引述《renderer (rendering)》之銘言: : : 個人覺得 在這種情況下 不必限制基礎類別一定要是純的抽象類別 : : 並禁止產生基礎類別物件 : : 只要把 int operator[](int) 設成 virtual : : 並加一個 virtual destructor 即可 : : 對於 virtual method 子類別有權利重新定義其運作 : 將公共繼承架構下的非末端類別都抽象化 可參考 S. Meyers 的 : More Effective C++ : Item 33, 寫的相當長 理由實在難以簡述 : 不過項目的名稱我倒是不會忘記 基本上 ME 條款 33 是對的。不過原 post 的主要問題並不在這裏。 我的看法是,原 post 不應該用 public 的方式繼承 class Base 因為很明顯的原 post 的目的只是精鍊程式碼,應該用 is-implemented-in-terms-of,而不是用 "isa" 的方式來表現, 所以頂多用 protected 繼承就足夠(Base class 的操作也調整為 protected),甚至在此不該用繼承,而該用合成(has-a)的方式 來實現。(另可參考四人幫 DP 的經典著作,優先用合成而非繼承) 簡單地說,不要濫用繼承!雖然它是很有力的機制,但也是兩面刃, 用不得當的話,負擔也很會「有力」。 相關的議題還有 Effective C++ 的條款 36 及條款 37,像原 post 的設計就明顯違反了後者。 大概說一下,首先是條款 37,絕對不要重新定義繼承而來的非虛擬 函式。在物件導向式的設計中,這基本上是錯誤的。因為這種設計 沒有享受到 OO 所提供「多型」的任何好處,而且還帶來的麻煩和 危險。至於詳細的理由大家自己翻書吧,要言之,這麼做根本就違 反 public 繼承的意義。 另外條款 36,這個也很重要,即使看完整本厚厚的 C++ Primer 和 The C++ Programming Language 兩本大部頭,對於這部份多半還是 會迷迷冒冒。簡單引用結論: ◎宣告一個純虛擬函式的目的,是為了讓 derived classes 只繼承  介面。 ◎宣告非純虛擬函式的目的,是為了讓 derived classes 繼承該函  式的介面和預設行為。 ◎宣告非虛擬函式的目的,是為了讓 derived classes 繼承其介面  及實作。 繼承(與虛擬函式配合)使用的時機也是一門學問。class 代表一種 概念,所謂「介面」,就是指一組設計中,class 與 class 之間( 也就是概念與概念之間)「抽象」(共同、不變)的部份,而「實作」 則是指設計中概念與概念之間「變異」的部份。這三種層次(純虛擬、 非純虛擬、非虛擬)的繼承,就分別表現出對「抽象性」和「變異性」 不同程度的對映。 再次強調,不要拘泥或在語法上鑽牛角尖,而是了解每個特徵(機制) 的原理及應用時機。C++ 並不限制繼承只有上面三種用法,但如果連 上面三種基本用法都沒搞清楚,就自己發明其他古怪的用法,通常是 自找麻煩。 以上三種用法是 OO 設計的基本準則。不代表除此之外的用法都不行, 例如條款 37,雖然它是很不好的設計,至少 C++ 編譯是可以接受的。 (但是這三種基本以外的用法,每一種都有它的額外負擔和必須承受 的風險,如果不是對它的好處和壞處都瞭如指掌,最好是完全避免使 用;尤其在團隊工作時,絕對不要特立獨行。) 另外還有條款 35 中的,「鳥會飛;企鵝是鳥;企鵝會飛?」及「正 方形繼承矩形?」幾個問題的探討,也有助於了解繼承的真實意義和 限制,大家有空多翻翻書吧。 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 59.120.214.120 ※ 編輯: cppOrz 來自: 59.120.214.120 (11/23 23:03)
UNARYvvv:推推推 11/23 23:42
renderer:推 11/24 08:54