CRTP是C++中通过派生类继承自身为模板参数的基类模板实现静态多态的惯用法,编译期绑定、零运行时开销;典型用途包括实例计数、强制接口实现和操作符复用,与虚函数动态多态目标不同、不可混用。

CRTP(Curiously Recurring Template Pattern,奇异递归模板模式)是C++中一种利用模板和继承实现静态多态的惯用法:派生类以自身作为模板参数,继承自一个以它为参数的基类模板。它在编译期就确定调用关系,无需虚函数表,零运行时开销。
核心写法:派生类“递归”传入基类模板
关键在于基类是一个模板,而派生类继承时把**自己**作为模板实参传进去:
templateclass Base { public: void interface() { static_cast (this)->implementation(); // 编译期绑定 } }; class MyWidget : public Base
{ // 注意:这里传的是 MyWidget 自身 public: void implementation() { / 具体逻辑 / } };
这样,Base 就能安全地向下转型调用 MyWidget 的成员,且整个过程不涉及虚函数或动态查找。
典型用途:自动注入通用功能
CRTP 常用于在不侵入派生类的前提下,统一提供能力,比如:
立即学习“C++免费学习笔记(深入)”;
-
计数对象实例:基类模板维护静态计数器,每个派生类拥有独立计数(
Base和Base的计数互不影响) -
强制接口实现:基类在
interface()中调用纯虚语义的derived_func(),若派生类未定义,编译失败(比纯虚函数更早报错) -
操作符重载复用:如实现
operator==,基类模板通过static_cast比较两个派生对象的底层数据
与虚函数多态的本质区别
静态多态 ≠ 动态多态的简化版,而是设计目标不同:
- 虚函数:支持运行时异构容器(如
vector),靠指针/引用来统一调度,有虚表开销和间接跳转> - CRTP:要求类型在编译期已知,适用于泛型算法、mixin 风格增强、性能敏感场景(如数学库、序列容器适配器),无任何间接成本
- 不能混用:CRTP 对象无法被当作同一基类指针存放——因为
Base和Base是完全不同的类型,没有公共父类
注意点:避免常见陷阱
使用 CRTP 要小心语法和语义边界:
- 派生类必须在定义完成后才可作为模板实参(不能前置声明后直接继承)
- 基类中访问派生类成员时,需确保该成员在基类函数被实例化时已声明(通常把基类函数定义放在派生类之后,或用
inline定义在头文件中) - 不要试图在基类中取派生类的
sizeof或声明其完整对象(此时派生类是不完全类型),但指针/引用没问题









