條款 19:設計 class 猶如設計 type

weixin_33936401發表於2017-07-25

Effective C++ 中文版 第三版》讀書筆記

** 條款 19:設計 class 猶如設計 type **

如何設計高效的 class呢?幾乎每一個 class 都要求你面對以下提問,而你的回答往往導致你的設計規範:

  1. 新 Type 的物件應該如何被建立和銷燬?
    這會影響到你的 class 的建構函式和解構函式以及記憶體分配函式和釋放函式(operator new、operator new[]、operator delete 和 operator delete[])的設計,當然前提是你打算撰寫他們。

  2. 物件的初始化和物件的賦值該有什麼樣的差別?
    這個答案決定你的建構函式和賦值操作符的行為,以及其間的差異。很重要的是別混淆了“初始化”和“賦值”,因為它們對應於不同的函式呼叫。

  3. 新 Type 的物件如果被 passed by value(以值傳遞),意味著什麼?
    記住,copy 建構函式用來定義一個 type 的 pass-by-value 該如何實現。

  4. 什麼是新 type 的“合法值”?
    對 class 的成員變數而言,通常只有某些數值集是有效的。那些數值集決定了你的 class 必須維護的約束條件,也就決定了你的成員函式(特別是建構函式、賦值操作符和所謂 “setter” 函式)必須進行的錯誤檢查工作。他也影響函式丟擲的異常、以及(極少被使用的)函式異常明細列。

  5. 你的新 type 需要配合某個繼承圖系(inheritance graph)嗎?
    如果你是繼承自某些既有的 class,你就受到那些 class 的設計的束縛,特別是受到“它們的函式時 visual 和 non-visual”的影響(條款34和36)。如果你允許其它 class 繼承你的 class,那會影響你所宣告的函式——尤其是解構函式——是否為 visual(條款07)。

  6. 你的新 type 需要什麼樣的轉換?
    你的 type 生存於其他一海票 types 之間,因而彼此之間該有轉換嗎?如果你希望允許型別 T1 之物被隱式轉換為型別 T2 之物,就必須在 class T1 內寫一個型別轉換函式(operator T2)或在 class T2 內寫一個 non-explicit-one-argument(可被單一實參呼叫)的建構函式。如果你允許 explicit 建構函式存在,就得寫出專門負責執行轉換的函式,且不得為型別轉換操作符 (type conversion operator) 或 non-explicit-one-argument 建構函式(條款15)。

  7. 什麼樣的操作符和函式對此新 type 而言是合理的?
    這個問題的答案決定你將為你的 class 宣告那些函式。其中某些該是 member 函式,某些則否(條款23、24、46)。

  8. 什麼樣的標準函式應該駁回?
    那些正是你必須宣告為 private 者(條款06)。

  9. 誰該取用新的 type 的成員?
    這個提問可以幫助你決定那個成員為 public,那個為 protected,那個為 private。他也幫助你決定哪一個 class 和/或 function 應該是 friend,以及它們巢狀於另一個之內是否合理。

  10. 什麼是新 type 的“未宣告介面”(undecleared interface)?
    他對效率、異常安全性(條款29)以及資源運用(例如多工鎖定和動態記憶體)提供何種保證?你在這些方面提供的保證將為你的 class 實現程式碼加上相應的約束條件。

  11. 你的新 type 有多麼的一般化?
    或許你其實並非定義一個新 type,而是定義一整個 types 家族。果真如此你就不該定義一個新 class,而是定義一個新的 class template。

  12. 你真的需要一個新 type 嗎?
    如果只是定義新的 derived class 以便為既有的 class 新增機能,那麼說不定單純定義一或多個 non-member 函式或 template,更能夠達到目標。

這些問題不容易回答,所以定義出搞笑的 class 是一種挑戰,然而如果能夠設計出至少像 C++ 內建型別一樣好的使用者自定義類,一切汗水便都值得。

** 請記住: **
class 的設計就是 type 的設計,在定義一個新 type 之前,請確定你已經考慮過本條款覆蓋的所有討論主題。

相關文章