(轉載)C++ 巧用 include 合併不同類中相似的虛函數
[編輯] [转简体] (简体译文)概要
正文
以下內容轉載自知乎回答(有刪改) https://www.zhihu.com/question/564819820/answer/2750198351
北車註:原問題可以不看,看回答即可。若需要看也可以見 http://huidong.xyz/article.php?blog_id=474
知乎回答:
在 topling-zip 的 fsa(DFA, NFA 等等)庫中,爲了同時實現多態和性能,把內容相似的虛函數,放在單獨的頭文件中,然後在不同的實現類中 include 這些頭文件,就像這樣:
class Base { public: virtual void foo() = 0; }; class ConcretA : public Base { inline void low_level_operation() {...} public: #include "foo_impl.h" }; class ConcretB : public Base { inline void low_level_operation() {...} public: #include "foo_impl.h" };
// file foo_impl.h void foo() override { while (some_condition()) { low_level_operation(); } }
其中 foo 是一個對外開放的 api,其實現需要用到一個 low_level_operation(),該 low_level_operation 的功能非常簡單,例如 fsa 中的 state_move,而 foo 則比較複雜,例如 prefix_match。
不同的 FSA,其 low_level_operation 的實現各不相同,但 foo 的實現完全相同,這在設計模式中,是典型的 template method,但需要把 low_level_operation 設計爲虛函數,這樣會引入很大的開銷,例如 DoubleArrayTrie 作爲 FSA 的實現時,其 state_move 超級簡單,爲此虛函數的開銷就不可忽視。
十多年前我最開始的實現就是 CRTP(前面已有其它答主詳細講解了,我就不再囉嗦),但是 CRTP 的問題有:
重度使用 template,例如簡單的 low_level_operation 調用,要寫成
static_cast<const Derived*>(this)->low_level_operation()
編譯錯誤、Debug 信息晦澀難懂
多繼承時,麻煩更大
引入反向依賴
編譯速度慢
目標代碼尺寸大(主要是 Debug 信息會爆炸很多倍)
最終,我決定應用自己 20 年前總結的技巧:在 C 語言中實現模板函數的方法 - 知乎 (zhihu.com),再進一步精化,就得到了這個方案:返璞歸真。