C++中的CRTP全称是Curiously Recurring Template Pattern,即奇异递归模板模式。它让派生类将自己作为模板参数传给基类,从而在基类里通过静态转换调用派生类的方法,实现编译期确定的多态,避免虚函数带来的运行时开销。

CRTP的基本写法
CRTP的核心在于基类是一个模板类,接受派生类作为模板参数。基类提供通用接口,内部用static_cast将this转为派生类指针来调用具体实现。
// 基类模板,Derived是派生类类型
template <typename Derived>
class Base {
public:
void interface() {
// 静态转换调用派生类实现
static_cast<Derived*>(this)->implementation();
}
// 可选默认实现
void implementation() {
// 基类默认行为
}
};
// 派生类将自身作为模板参数传给Base
class DerivedA : public Base<DerivedA> {
public:
void implementation() {
// 派生类具体逻辑
}
};
class DerivedB : public Base<DerivedB> {
public:
void implementation() {
// 另一个派生类逻辑
}
};
使用CRTP实现静态多态
静态多态指在编译期就确定调用的函数,不需要虚表查找。下面示例展示如何用CRTP统一调用不同派生类的方法。
#include <iostream>
template <typename Derived>
class Shape {
public:
void draw() {
static_cast<Derived*>(this)->draw_impl();
}
};
class Circle : public Shape<Circle> {
public:
void draw_impl() {
std::cout << "Draw Circle" << std::endl;
}
};
class Square : public Shape<Square> {
public:
void draw_impl() {
std::cout << "Draw Square" << std::endl;
}
};
template <typename T>
void render(Shape<T>& s) {
s.draw();
}
int main() {
Circle c;
Square s;
render(c);
render(s);
return 0;
}
为什么CRTP能提高运行效率
使用虚函数时,每次调用都要通过虚表指针查找函数地址,这会带来额外指令和缓存不友好。CRTP在编译期通过static_cast直接绑定到具体函数,通常可被内联优化,消除了间接调用成本。
| 对比项 | 虚函数多态 | CRTP静态多态 |
|---|---|---|
| 绑定时间 | 运行时 | 编译期 |
| 调用开销 | 虚表查找 | 直接内联 |
| 灵活性 | 可运行时切换 | 类型固定 |
适用场景与注意点
- 对性能敏感且类型在编译期已知的模块,如数学库、游戏引擎组件。
- 需要为多个类型提供统一接口但不想承担虚函数成本时。
- CRTP会增加模板代码膨胀,且不支持运行时多态,应按需选用。
CRTP不是虚函数的替代品,而是另一种工具。理解它的静态分发本质,才能在正确场景用它提升效率。
简单计数基类示例
template <typename T>
class Counter {
static int count;
public:
Counter() { ++count; }
static int get_count() { return count; }
};
template <typename T>
int Counter<T>::count = 0;
class A : public Counter<A> {};
class B : public Counter<B> {};
// A和B有各自独立的计数器
小结
CRTP通过模板递归让基类感知派生类,用静态转换代替虚调用,是C++实现静态多态、提高运行效率的实用手法。写法是基类模板取派生类为参数,派生类继承时回传自身,接口中转换调用即可。
CRTPC++_templatestatic_polymorphism修改时间:2026-07-26 16:09:12