條款19 設計class 猶如設計type

Sunshine_top發表於2015-03-12

在 C++ 中,就像其它物件導向程式語言,可以通過定義一個新的類來定義一個新的型別。作為一個C++開發者,你的大量時間就這樣花費在擴張你的型別系統。這意味著你不僅僅是一個類的設計者,而且是一個型別的設計者。過載函式和運算子,控制記憶體分配和回收,定義物件的初始化和終結過程——這些全在你的掌控之中。因此你應該在類設計中傾注大量心血,就如語言設計者在語言內建型別設計中所傾注的大量心血。

設計良好的類是有挑戰性的,因為設計良好的型別是有挑戰性的。良好的型別擁有簡單自然的語法,符合直覺的語義,以及一個或更多高效的實現。那麼,如何才能設計高效的類呢?首先,你必須理解你所面對的問題。實際上每一個類都需要你面對下面這些問題,其答案通常就導向你的設計規範:

·    新型別的物件應該如何建立和銷燬?如何做這些將影響到你的類的建構函式和解構函式,以及記憶體分配和回收函式(operator new,operator new[],operator delete,和 operator delete[])的設計,除非你不寫它們。

·    物件的初始化和物件的賦值應該有什麼不同?這個問題的答案決定了你的建構函式和賦值運算子的行為以及它們之間的不同。

·    值傳遞(passed by value)對於新型別的物件意味著什麼?拷貝建構函式定義了一個新型別的傳值如何實現。

·    新型別的合法值是什麼?通常,對於一個類的資料成員來說,僅有某些值的組合是合法的。那些數值集決定了你的類必須維護的約束條件。也決定了必須在成員函式內部進行的錯誤檢查,特別是建構函式,賦值運算子,以及"setter"函式。它可能也會影響函式丟擲的異常,以及(極少被使用的)函式異常明細(exceptionspecification)。

·    你的新型別需要配合某個繼承圖系中?如果你從已經存在的類繼承,你就受到那些類的設計約束,特別受到它們的函式是virtual還是non-virtual的影響。如果你希望允許其他類繼承你的類,將影響到你是否將函式宣告為virtual,特別是你的解構函式。

·    你的新型別允許哪種型別轉換?你的型別身處其它型別的海洋中,所以是否要在你的型別和其它型別之間有一些轉換?如果你希望允許 T1 型別的物件隱式轉型為 T2 型別的物件,你就要麼在T1類中寫一個型別轉換函式(如operator T2),要麼在 T2 類中寫一個non-explicit-one argument建構函式。如果你只允許顯示建構函式存在,就得寫出專門負責執行轉換的函式,且不得為型別轉換操作符或non-explicit-oneargument建構函式。

·    對於新型別哪些運算子和函式是合理的?這個問題的答案決定你為你的類宣告哪些函式。其中一些是成員函式,另一些不是。

·    哪些標準函式應該駁回?你需要將那些都宣告為 private。

·    你的新型別中哪些成員可以被訪問?這個問題的可以幫助你決定哪些成員是 public,哪些是 protected,以及哪些是 private。它也可以幫助你決定哪些類 和/或 函式應該是友元,以及一個類巢狀在另一個類內部是否有意義。

·    什麼是新型別的未宣告介面 "undeclaredinterface"?它對於效率,異常安全,以及資源使用(例如,多工鎖定和動態記憶體)提供哪種保證?你在這些領域提供的保證將為你的類的實現程式碼加上相應的約束條件。

·    你的新型別有多大程度的通用性?也許你並非真的要定義一個新的型別,也許你要定義一整個型別家族。如果是這樣,你就不該定義一個新的類,而應該定義一個新的類别範本。

·    一個新的型別真的是你所需要的嗎?是否你可以僅僅定義一個新的繼承類,以便讓你可以為一個已有的類增加一些功能,也許通過簡單地定義一個或更多非成員函式或模板能更好地達成你的目標。

·    類設計就是型別設計。定義高效的類是有挑戰性的。在C++中使用者自定義類生成的型別最好可以和內建型別一樣好。

相關文章