看板 C_and_CPP 關於我們 聯絡資訊
class如何設計,這個題目太大了 沒辦法只用一篇文章交待完畢,下面只能提我想到的 (1)class vs struct vs union union用途比較特殊,不再特別提 traits、metafunction、functor,使用struct 有不變式者使用class,否則用struct 補充: 這裡說明一下如何判斷有無不變式 當data成員可以各自任意獨立變更內容時,表示沒有不變式 例如一個類別有月、日欄位,哪些日合法要看月的值,有不變式 或是有一欄位表示元素數量,一欄位指向各元素存放位置,也有不變式 (2)3/5/0法則 除非必要,否則不要自己寫copy、move、dtor 如果寫了其中一個,通常也要寫其他四個成員函數 (3)obj成員 vs ptr成員 vs ref成員 先判斷採組合還是聚合,再判斷是否有降低類型相依性的需要 smart ptr,有所有權 raw ptr,盡量讓其沒有所有權(見補充) ref,沒有所有權,而且不能改變值 盡量用std::function取代函數指標 補充: C++ Core Guidelines R.3與R.4,建議讓raw ptr與ref沒有所有權 但raw ptr有例外,例如舊代碼,或是底層實作的需要 (4)static成員 vs non-static成員 成員基於類別,static成員 成員基於物件,non-static成員 (5)public權限 vs private權限 vs protected權限 data成員: 各成員之間有不變式關係,private權限 各成員之間無不變式關係,public權限 避免protected data non-const data權限要一樣 成員函數: 提供給任意使用者的介面,public權限 僅提供給子類的介面,protected權限 只提供類別內部使用,private權限 (6)public繼承 vs private繼承 vs protected繼承 有"IS-A"或"-ABLE"關係,繼承介面(可能還有實作),public繼承 有"HAS-A"關係,僅繼承實作,private繼承 補充: http://www.gotw.ca/publications/mill06.htm private繼承跟protected繼承可以用在受控制的多型 這用途很罕見,所以protected繼承基本上可以忽略 (7)private繼承 vs 組合 在"HAS-A"關係的前提下考慮這個 優先用組合,除非以下情況(細節見Effective C++ Item 39) 為了節省empty class佔用的空間 需要用到protected成員 需要改寫父類的virtual函數,例如template pattern (8)public繼承 vs 組合 https://isocpp.org/wiki/faq/multiple-inheritance 看上面連結的經驗法則1 主要目的是代碼重用時,組合 主要目的是多型時,繼承 補充: 記住,繼承的耦合度高於組合 繼承的主要目的不是代碼重用,盡量避免實作繼承 (9)virtual函數 vs non-virtual函數 讓子類只繼承介面,pure virtual函數 讓子類繼承介面跟預設實作,impure virtual函數 提供預設實作並強迫子類顯式呼叫,為pure virtual函數提供定義 讓子類繼承介面跟強制實作,non-virtual函數 讓子類只改寫方法的某些步驟,用NVI包裝virtual函數(template pattern) 多型類別必須有virtual dtor 補充: 記得預設參數是靜態綁定,不要試圖改寫 (10)operator overloading 除非必要,否則不要重寫 盡量避免重寫operator&&跟operator||,會失去短路求值特性 盡量避免重寫unary &,遇到incomplete type會導致結果無法預期 operator+以operator+=來實作,以此類推 operator+設計成非成員函數,operator+=設計成成員函數,以此類推 unary設計成成員函數,binary設計成非成員函數 postfix ++以prefix ++實作,以此類推 operator=不要設virtual 如果重寫類型轉換函數,請宣告成explicit,除非希望隱式轉換 (11)ctor 不要自己寫一個只初始data成員的default ctor 單參數ctor(不含copy跟move)宣告成explicit,除非希望隱式轉換 初始過程如果想要有虛函數的行為,請改用factory pattern 考慮是否需要用using繼承父類的ctor (12)多型類別禁止public copy/move 如果想複製,請改用prototype pattern (13)exception safety dtor、swap、move、回收函數必須做到nothrow default ctor、operator==(含其他比較運算子)盡量做到nothrow (14)當函數需要直接存取內部成員時才作為成員函數 以下為例外情況: 虛函數 operator overloading另有一套判斷方式 重載集合不是每個函數都會直接存取內部成員 返回this的函數 (15)如果有作為成員函數的需要,再繼續判斷是否改用friend函數 https://isocpp.org/wiki/faq/friends 第一個函數參數不是該物件本身(見補充),friend函數 涉及binary運算,friend函數 其餘情況,優先用成員函數 補充: 應該是在講std::invoke (16)friend函數 vs static成員函數 vs non-static成員函數 如果經過(14)跟(15)仍無法決定,可以繼續參考下面 如果無法用ADL找到該函數的聲明,不考慮friend函數 如果需要相當於this的參數,不考慮static成員函數 如果不要相當於this的參數,不考慮non-static成員函數 補充: http://www.gotw.ca/publications/mill02.htm 非成員函數如果不滿足介面原則,就沒有設計成friend的意義 static成員函數如果需要this,就沒有不用non-static版本的理由 (17)const成員函數 vs non-const成員函數 除非確實需要修改data成員,否則選擇const成員函數 (18)動態多型 vs 靜態多型 優先使用動態多型,除非有用CRTP消除virtual函數開銷的必要 (19)函數的定義是否放在class body 為了降低編譯相依性或不要inline,不放 為了可讀性或inline,放 補充: virtual函數不會inline,ctor跟dtor盡量不要inline 除非必要,否則不考慮函數是否inline 函數定義如果不放在class body,則定義應放在cpp檔 (20)多重繼承 https://isocpp.org/wiki/faq/multiple-inheritance 考慮bridge pattern跟nested generalization能否作為替代方案 補充: 使用多重繼承需要很多前置知識,謹慎使用 (21)虛擬繼承 虛擬繼承的主要用途是搭配多重繼承 盡量避免在virtual base放data (22)如果需要限制繼承深度 優先考慮final 限制之後往下最多可以繼承幾層,虛擬繼承 + private ctor (23)design pattern 視使用情境而定,例如 strategy,動態切換演算法 adapter,解決介面不相容的問題 singleton,確保一個類只有一個實例 (24)mixin 主要目的是代碼重用,由任意個元件組成一個新類別,有下面兩種方式實現 可變模板 + 多重繼承,每個基類皆為一個元件 模板 + 單繼承,每層皆為一個元件 補充: 每個元件功能盡可能單一化,且採public繼承 public繼承一般不是為了代碼重用,所以使用mixin前請先了解一般的繼承用法 多重繼承版本,mixin元件可以共享方法,但要轉型才能使用 單繼承版本,mixin元件只能單向共享內層的方法,不用轉型就能使用 (25)常數 執行期常數,const 編譯期常數 + 有使用具名enum的必要,enum class 編譯期常數 + 一般情況,constexpr 補充: enum每個常數之間要有足夠的關聯,不能只用來包裝一堆無關常數 用enum class取代enum,可以防止隱式轉型及名稱污染 (26)類型成員 nested class:不要同時定義class及聲明該類型的變數 enum:不要同時定義enum及聲明該類型的變數 類型別名:用using取代typedef,因為前者可讀性高又能用在alias template 補充: data成員、成員函數、類型成員應按性質各自集中擺放 故類型成員不宜跟data成員混在一起 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 36.237.69.224 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1624780030.A.7B4.html
beatssola: 推06/28 01:20
loveflames: 再增加一項,因為static成員函數有辦法間接存取non-st06/28 18:45
loveflames: atic成員06/28 18:45
※ 編輯: loveflames (36.237.69.224 臺灣), 06/28/2021 18:48:25
FY4: 推 06/28 23:50
KanzakiHAria: singleton最簡單的方式把解構建構private 06/29 01:13
KanzakiHAria: 加個return static local自己的get instance函數 06/29 01:14
loveflames: 話說policy based design我找不到不改成組合的理由 06/29 10:02
loveflames: 而組合沒辦法取代mixin的橫向展延性質 06/29 10:04
unmolk: 感謝分享!獲益良多 07/02 17:26
shibin: 推 07/02 19:09
※ 編輯: loveflames (125.227.113.163 臺灣), 07/06/2021 12:10:58
loveflames: 後來補上幾個新項目 07/06 12:11
hhashoww: 新手看不懂 但還是推! 感謝整理 07/24 18:41
loveflames: 語法看到一定程度應該就看得懂了,這篇主要是提供選 07/25 00:21
loveflames: 擇的方式 07/25 00:21