核心模式 (CRTP)
template <class Derived>
class Base {
public:
void interface() { static_cast<Derived*>(this)->implementation(); }
protected:
Base() = default;
};
class Derived : public Base<Derived> {
friend class Base<Derived>;
void implementation() { /* 具體實作 */ }
};
Base 模板參數為衍生類別 Derived。
static_cast<Derived*>(this) 安全下轉 (編譯期已知型別)。
- 衍生類別在
implementation 實作具體行為,基類提供通用介面。
靜態 vs 動態多態效能對比
測試環境:Linux x86_64, GCC, 1 億次迴圈調用簡單增減操作。
| 建置模式 | 虛函數耗時 | CRTP 耗時 | 加速比 |
| 無優化 (-O0) | 1.04 秒 | 1.63 秒 | 虛函數略快 (CRTP 未內聯) |
| 優化 (-O2/-O3) | 0.62 秒 | 0.056 秒 | CRTP 快 11 倍 |
原因分析
- 虛函數:間接呼叫 (vtable 查找),編譯器**無法內聯** (動態綁定),優化受限。
- CRTP:
static_cast + 直接呼叫,編譯器**完全內聯**展開,消除呼叫開銷,進一步優化迴圈內部邏輯。
- 優化開啟時,虛函數仍保留間接跳轉;CRTP 變為純量運算,指令流極短。
適用與不適用場景
| 場景 | 推薦 | 理由 |
| 高頻熱路徑、簡單介面、型別封閉 | CRTP | 極致效能、零開銷抽象 |
| 動態載入插件、跨 DLL 介面 | 虛函數 | 二進位相容、型別抹除 |
| 大型類別體系、多重繼承 | 虛函數 | CRTP 單一繼承限制、編譯期膨脹 |
| 需要運行期切換實作 | 虛函數 / std::function | CRTP 編譯期綁定 |
現代 C++ 補充
- C++20 **Concepts** 可約束
Derived 需提供的介面,提前報錯。
- 配合
final 關鍵字防止進一步繼承破壞靜態綁定假設。
- 標準庫大量使用 CRTP:
std::iterator (C++17 deprecated), std::enable_shared_from_this, boost::intrusive 等。
結語
CRTP 是 C++ **零開銷抽象** 的經典範例。在效能敏感、型別固定的熱路徑中,優先考慮 CRTP 替代虛函數;通用介面、擴充性優先場景仍以虛函數為主。兩者並非互斥,可混合使用 (基類虛函數 + CRTP 葉子類別)。
- 上一篇文章: WINX 視窗類物件記憶體管理:基於 Owner 的生命週期模型
- 下一篇文章: C++ 預設建構函數完整規則與陷阱
Copyright ©
程式碼之家 All Rights Reserved