# Item 19: 視類設計為類型設計
作者:Scott Meyers
譯者:fatalerror99 (iTePub's Nirvana)
發布:http://blog.csdn.net/fatalerror99/
在 C++ 中,就像其它面向對象編程語言,可以通過定義一個新的類來定義一個新的類型。作為一個 C++ 開發者,你的大量時間就這樣花費在增大你的類型系統。這意味著你不僅僅是一個類的設計者,而且是一個類型的設計者。重載函數和運算符,控制內存分配和回收,定義對象的初始化和終結過程——這些全在你的掌控之中。因此你應該在類設計中傾注大量心血,接近語言設計者在語言內建類型的設計中所傾注的大量心血。
設計良好的類是有挑戰性的,因為設計良好的類型是有挑戰性的。良好的類型擁有簡單自然的語法,符合直覺的語義,以及一個或更多高效的實現。在 C++ 中,一個缺乏計劃的類設計,使其不可能達到上述任何一個目標。甚至一個類的成員函數的執行特性可能受到它們是被如何聲明的影響。
那么,如何才能設計高效的類呢?首先,你必須理解你所面對的問題。實際上每一個類都需要你面對下面這些問題,其答案通常就導向你的設計的限制因素:
* 你的新類型的對象應該如何創建和銷毀?如何做這些將影響到你的類的構造函數和析構函數,以及內存分配和回收的函數(operator new,operator new[],operator delete,和 operator delete[] ——參見 Chapter 8)的設計,除非你不寫它們。
* 對象的初始化和對象的賦值應該有什么不同?這個問題的答案決定了你的構造函數和你的賦值運算符的行為和它們之間的不同。這對于不混淆初始化和賦值是很重要的,因為它們相當于不同的函數調用(參見 Item 4)。
* 以值傳遞(passed by value)對于你的新類型的對象意味著什么?記住,拷貝構造函數定義了一個新類型的傳值(pass-by-value)如何實現。
* 你的新類型的合法值的限定條件是什么?通常,對于一個類的數據成員來說,僅有某些值的組合是合法的。那些組合決定了你的類必須維持的不變量。這些不變量決定了你必須在成員函數內部進行錯誤檢查,特別是你的構造函數,賦值運算符,以及 "setter" 函數。它可能也會影響你的函數拋出的異常,以及你的函數的異常規范(exception specification)(你用到它的可能性很小)。
* 你的新類型是否適合放進一個繼承圖表中?如果你從已經存在的類繼承,你將被那些類的設計所約束,特別是它們的函數是 virtual 還是 non-virtual(參見 Item 34 和 36)。如果你希望允許其他類繼承你的類,將影響到你是否將函數聲明為 virtual,特別是你的析構函數(參見 Item 7)。
* 你的新類型允許哪種類型轉換?你的類型身處其它類型的海洋中,所以是否要在你的類型和其它類型之間有一些轉換?如果你希望允許 T1 類型的對象隱式轉型為 T2 類型的對象,你就要么在 T1 類中寫一個類型轉換函數(例如,operator T2),要么在 T2 類中寫一個非顯式的構造函數,而且它們都要能夠以單一參數調用。如果你希望僅僅允許顯示轉換,你就要寫執行這個轉換的函數,而且你還需要避免使它們的類型轉換運算符或非顯式構造函數能夠以一個參數調用。(作為一個既允許隱式轉換又允許顯式轉換的例子,參見 Item 15。)
* 對于新類型哪些運算符和函數有意義?這個問題的答案決定你應該為你的類聲明哪些函數。其中一些是成員函數,另一些不是(參見 Item 23、24 和 46)。
* 哪些標準函數不應該被接受?你需要將那些都聲明為 private(參見 Item 6)。
* 你的新類型中哪些成員可以被訪問?這個問題的可以幫助你決定哪些成員是 public,哪些是 protected,以及哪些是 private。它也可以幫助你決定哪些類和/或函數應該是友元,以及一個類嵌套在另一個類內部是否有意義。
* 什么是你的新類型的 "undeclared interface"?它對于性能考慮,異常安全(exception safety)(參見 Item 29),以及資源使用(例如,鎖和動態內存)提供哪種保證?你在這些領域提供的保證將強制影響你的類的實現。
* 你的新類型有多大程度的通用性?也許你并非真的要定義一個新的類型。也許你要定義一個整個的類型家族。如果是這樣,你不需要定義一個新的類,而是需要定義一個新的類模板。
* 一個新的類型真的是你所需要的嗎?是否你可以僅僅定義一個新的繼承類,以便讓你可以為一個已存在的類增加一些功能,也許通過簡單地定義一個或更多非成員函數或模板能更好地達成你的目標。
回答這些問題是困難的,所以定義高效的類是有挑戰性的。既然,在 C++ 中用戶自定義類生成的類型至少可以和內建類型一樣好,那就做好它,它會使一切努力都變的有價值。
Things to Remember
* 類設計就是類型設計。定義一個新類型之前,確保考慮了本 Item 討論的所有問題。
- Preface(前言)
- Introduction(導言)
- Terminology(術語)
- Item 1: 將 C++ 視為 federation of languages(語言聯合體)
- Item 2: 用 consts, enums 和 inlines 取代 #defines
- Item 3: 只要可能就用 const
- Item 4: 確保 objects(對象)在使用前被初始化
- Item 5: 了解 C++ 為你偷偷地加上和調用了什么函數
- Item 6: 如果你不想使用 compiler-generated functions(編譯器生成函數),就明確拒絕
- Item 7: 在 polymorphic base classes(多態基類)中將 destructors(析構函數)聲明為 virtual(虛擬)
- Item 8: 防止因為 exceptions(異常)而離開 destructors(析構函數)
- Item 9: 絕不要在 construction(構造)或 destruction(析構)期間調用 virtual functions(虛擬函數)
- Item 10: 讓 assignment operators(賦值運算符)返回一個 reference to *this(引向 *this 的引用)
- Item 11: 在 operator= 中處理 assignment to self(自賦值)
- Item 12: 拷貝一個對象的所有組成部分
- Item 13: 使用對象管理資源
- Item 14: 謹慎考慮資源管理類的拷貝行為
- Item 15: 在資源管理類中準備訪問裸資源(raw resources)
- Item 16: 使用相同形式的 new 和 delete
- Item 17: 在一個獨立的語句中將 new 出來的對象存入智能指針
- Item 18: 使接口易于正確使用,而難以錯誤使用
- Item 19: 視類設計為類型設計
- Item 20: 用 pass-by-reference-to-const(傳引用給 const)取代 pass-by-value(傳值)
- Item 21: 當你必須返回一個對象時不要試圖返回一個引用
- Item 22: 將數據成員聲明為 private
- Item 23: 用非成員非友元函數取代成員函數
- Item 24: 當類型轉換應該用于所有參數時,聲明為非成員函數
- Item 25: 考慮支持不拋異常的 swap
- Item 26: 只要有可能就推遲變量定義
- Item 27: 將強制轉型減到最少
- Item 28: 避免返回對象內部構件的“句柄”
- Item 29: 爭取異常安全(exception-safe)的代碼
- Item 30: 理解 inline 化的介入和排除
- Item 31: 最小化文件之間的編譯依賴
- Item 32: 確保 public inheritance 模擬 "is-a"
- Item 33: 避免覆蓋(hiding)“通過繼承得到的名字”
- Item 34: 區分 inheritance of interface(接口繼承)和 inheritance of implementation(實現繼承)
- Item 35: 考慮可選的 virtual functions(虛擬函數)的替代方法
- Item 36: 絕不要重定義一個 inherited non-virtual function(通過繼承得到的非虛擬函數)
- Item 37: 絕不要重定義一個函數的 inherited default parameter value(通過繼承得到的缺省參數值)
- Item 38: 通過 composition(復合)模擬 "has-a"(有一個)或 "is-implemented-in-terms-of"(是根據……實現的)
- Item 39: 謹慎使用 private inheritance(私有繼承)
- Item 40: 謹慎使用 multiple inheritance(多繼承)
- Item 41: 理解 implicit interfaces(隱式接口)和 compile-time polymorphism(編譯期多態)
- Item 42: 理解 typename 的兩個含義
- Item 43: 了解如何訪問 templatized base classes(模板化基類)中的名字
- Item 44: 從 templates(模板)中分離出 parameter-independent(參數無關)的代碼
- Item 45: 用 member function templates(成員函數模板) 接受 "all compatible types"(“所有兼容類型”)
- Item 46: 需要 type conversions(類型轉換)時在 templates(模板)內定義 non-member functions(非成員函數)
- Item 47: 為類型信息使用 traits classes(特征類)
- Item 48: 感受 template metaprogramming(模板元編程)
- Item 49: 了解 new-handler 的行為
- Item 50: 領會何時替換 new 和 delete 才有意義
- Item 51: 編寫 new 和 delete 時要遵守慣例
- Item 52: 如果編寫了 placement new,就要編寫 placement delete
- 附錄 A. 超越 Effective C++
- 附錄 B. 第二和第三版之間的 Item 映射