作者loveflames (咕啾咕啾魔法陣)
看板C_and_CPP
標題[心得] 整理了一下多重繼承的相關概念或資料出處
時間Wed Jun 23 12:40:50 2021
(1)菱形繼承
導致了二義性問題,有幾種方式解決
一種是限制繼承深度,讓菱形繼承無法出現
一種是使用虛擬繼承,但虛擬繼承本身帶來以下問題(細節見Effective C++ Item 40)
虛基類初始順序較複雜
由最終派生類呼叫虛基類ctor,容易踩坑
佔比較多的空間,且影響data存取速度
(2)指標偏移
父類指標與子類指標指向同一實體,但位址未必相同
不過指標拿來做比較運算時相同,因為會隱式轉型成父類指標再比較
(3)轉型導致虛函數執行結果無法預期
第一種情況是涉及void*,導致轉型時指標不偏移
第二種情況是使用不偏移指標的轉型:reinterpret_cast
(4)More Effecitve C++ Item M24
影響效能且佔比較多的空間
(5)Google C++ Style Guide
多重繼承本身帶來的效能影響比虛擬繼承還高
避免多重實作繼承
(6)Effective C++ Item 40
public介面繼承 + private實作繼承
(7)C++ Core Guidelines C.135
用多重繼承表示多個不同的介面,這些介面通常是抽象類
(8)C++ Core Guidelines C.136
用多重繼承表示實現特性的合併;此item認為優先使用單一繼承
(9)Modern C++ Design
第一章的policy based design,結合多重繼承跟template
第三章的hierarchy generator,現在可以用variadic template簡化
(10)C++ Templates: The Complete Guide 21.3
mixin,能在不複製介面的情況下增加data成員或其他操作
為了增加任意數量的base,會用到variadic template
補充:
mixin跟policy based design都是多重實現繼承
前者與派生類有"-ABLE"的關係
後者強調在相同介面下選擇何種行為,而不是增加data成員或其他操作
前者應採用public繼承,後者應採用private繼承
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 125.227.113.163 (臺灣)
※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1624423252.A.26D.html
→ KanzakiHAria: 少用繼承多用組合 06/25 12:26
→ loveflames: 優先用組合是當然,不過講這個又要提bridge pattern了 06/25 12:28
→ loveflames: C++官網也有探討過這個 06/25 12:28
推 ShenJing: 感謝整理 06/25 15:03
既然推文提到優先使用組合,那麼就進一步討論這個
基本上就是因為繼承的耦合度比較高
除了編譯相依性外,修改父類很可能導致子類一起修改,我想了幾個可能情境
父類原本沒有與子類同名的函數,後來加上去
父類允許的繼承深度遭到改變
父類從一般繼承改成虛擬繼承祖父類
父類有無不變式(invariant)的性質遭到改變
(不知道不變式是什麼的,請參考Google C++ Style Guide跟C++ Core Guidelines)
另外,C++官網列了三個經驗法則
https://isocpp.org/wiki/faq/multiple-inheritance
經驗法則1:僅當這樣做會刪除if/switch語句時使用繼承
經驗法則2:多重繼承盡量繼承抽象類
經驗法則3:考慮bridge pattern跟nested generalization能否作為替代方案
如果採用以上連結內容的觀點
以二維(M種產品 + N種顏色)為例,考量三種方案的優缺點
多重繼承
優點:可同時為產品維度跟顏色維度提供多型
缺點:多重繼承跟虛擬繼承帶來的問題
可能是優點也可能是缺點:有M x N個實作類別
bridge pattern
優點:將顏色維度分離出去,繼承關係變成組合關係
缺點:無法在編譯期排除某些組合(例如:背包 + 黑色)
可能是優點也可能是缺點:有M + N個實作類別
nested generalization:
缺點:第一層產品維度 + 第二層顏色維度,無法共享顏色維度的代碼
可能是優點也可能是缺點:有M x N個實作類別
※ 編輯: loveflames (125.227.113.163 臺灣), 06/25/2021 16:21:34
推 KanzakiHAria: 推推 06/25 21:00
→ DerLuna: 不要用繼承 06/27 19:01