[心得] 關於設計class的衡量方式

看板C_and_CPP作者 (咕啾咕啾魔法陣)時間2年前 (2021/06/27 15:47), 2年前編輯推噓2(206)
留言8則, 4人參與, 2年前最新討論串1/1
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)public權限 vs private權限 vs protected權限 data成員: 各成員之間有不變式關係,private權限 各成員之間無不變式關係,public權限 避免protected data non-const data權限要一樣 成員函數: 提供給任意使用者的介面,public權限 僅提供給子類的介面,protected權限 只提供類別內部使用,private權限 (5)public繼承 vs private繼承 vs protected繼承 有"IS-A"或"-ABLE"關係,繼承介面(可能還有實作),public繼承 有"HAS-A"關係,僅繼承實作,private繼承 補充: http://www.gotw.ca/publications/mill06.htm private繼承跟protected繼承可以用在受控制的多型 這用途很罕見,所以protected繼承基本上可以忽略 (6)private繼承 vs 組合 在"HAS-A"關係的前提下考慮這個 優先用組合,除非遇到Effective C++ Item 39說的特殊情況 (7)public繼承 vs 組合 https://isocpp.org/wiki/faq/multiple-inheritance 看上面連結的經驗法則1 主要目的是代碼重用時,組合 主要目的是多型時,繼承 補充: 記住,繼承的耦合度高於組合 繼承的主要目的不是代碼重用,盡量避免實作繼承 (8)virtual函數 vs non-virtual函數 讓子類只繼承介面,pure virtual函數 讓子類繼承介面跟預設實作,impure virtual函數 提供預設實作並強迫子類顯式呼叫,為pure virtual函數提供定義 讓子類繼承介面跟強制實作,non-virtual函數 讓子類只改寫方法的某些步驟,用NVI包裝virtual函數(template pattern) 多型類別必須有virtual dtor 補充: 記得預設參數是靜態綁定,不要試圖改寫 (9)operator overloading 除非必要,否則不要重寫 盡量避免重寫operator&&跟operator||,會失去短路求值特性 盡量避免重寫unary &,遇到incomplete type會導致結果無法預期 operator+以operator+=來實作,以此類推 operator+設計成非成員函數,operator+=設計成成員函數,以此類推 unary設計成成員函數,binary設計成非成員函數 postfix ++以prefix ++實作,以此類推 operator=不要設virtual (10)ctor 不要自己寫一個只初始data成員的default ctor 單參數ctor(不含copy跟move)宣告成explicit,除非希望隱式轉換 初始過程如果想要有虛函數的行為,請改用factory pattern 考慮是否需要用using繼承父類的ctor (11)多型類別禁止public copy/move 如果想複製,請改用prototype pattern (12)exception safety dtor、swap、move、回收函數必須做到nothrow default ctor、operator==(含其他比較運算子)盡量做到nothrow (13)當函數需要直接存取內部成員時才作為成員函數 以下為例外情況: 虛函數 operator overloading另有一套判斷方式 重載集合不是每個函數都會直接存取內部成員 返回this的函數 (14)如果有作為成員函數的需要,再繼續判斷是否改用friend函數 https://isocpp.org/wiki/faq/friends 該物件本身所在的函數參數位置不是第一個(見補充),friend函數 涉及binary運算,friend函數 其餘情況,優先用成員函數 補充: 應該是在講std::invoke (15)const成員函數 vs non-const成員函數 除非確實需要修改data成員,否則選擇const成員函數 (16)static成員 vs non-static成員 成員基於類別,static成員 成員基於物件,non-static成員 (17)動態多型 vs 靜態多型 優先使用動態多型,除非有用CRTP消除virtual函數開銷的必要 (18)函數的定義是否放在class body 為了降低編譯相依性或不要inline,不放 為了可讀性或inline,放 補充: virtual函數不會inline,ctor跟dtor盡量不要inline 除非必要,否則不考慮函數是否inline (19)多重繼承 https://isocpp.org/wiki/faq/multiple-inheritance 考慮bridge pattern跟nested generalization能否作為替代方案 補充: 使用多重繼承需要很多前置知識,謹慎使用 (20)虛擬繼承 虛擬繼承的主要用途是搭配多重繼承 盡量避免在virtual base放data (21)如果需要限制繼承深度 優先考慮final 限制之後往下最多可以繼承幾層,虛擬繼承 + private ctor (22)design pattern 視使用情境而定,例如 strategy,動態切換演算法 adapter,解決介面不相容的問題 singleton,確保一個類只有一個實例 (23)friend函數 vs static成員函數 vs non-static成員函數 如果經過(13)跟(14)仍無法決定,可以繼續參考下面 如果無法用ADL找到該函數的聲明,不考慮friend函數 如果需要相當於this的參數,不考慮static成員函數 如果不要相當於this的參數,不考慮non-static成員函數 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 36.237.69.224 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1624780030.A.7B4.html

06/28 01:20, 2年前 , 1F
06/28 01:20, 1F

06/28 18:45, 2年前 , 2F
再增加一項,因為static成員函數有辦法間接存取non-st
06/28 18:45, 2F

06/28 18:45, 2年前 , 3F
atic成員
06/28 18:45, 3F
※ 編輯: loveflames (36.237.69.224 臺灣), 06/28/2021 18:48:25

06/28 23:50, 2年前 , 4F
06/28 23:50, 4F

06/29 01:13, 2年前 , 5F
singleton最簡單的方式把解構建構private
06/29 01:13, 5F

06/29 01:14, 2年前 , 6F
加個return static local自己的get instance函數
06/29 01:14, 6F

06/29 10:02, 2年前 , 7F
話說policy based design我找不到不改成組合的理由
06/29 10:02, 7F

06/29 10:04, 2年前 , 8F
而組合沒辦法取代mixin的橫向展延性質
06/29 10:04, 8F
文章代碼(AID): #1Ws2p-Uq (C_and_CPP)