奇异递归
奇异递归(Curiously Recurring Template Pattern,CRTP) 是一种C++模板编程技术,其核心思想是:一个类(派生类)将自己作为模板参数传递给其基类。这种模式通过编译时多态(静态多态)实现类似运行时多态的行为,但避免了虚函数的开销。
基本结构
template <typename Derived> class Base { // 基类通过模板参数Derived访问派生类的成员 }; class Derived : public Base<Derived> { // 派生类将自己作为模板参数传递给基类 // 派生类实现 };
核心特点
- 编译时多态基类通过static_cast<Derived*>(this)直接调用派生类的方法,无需虚函数表(vtable)的开销。
- 派生类自我引用派生类继承时,将自己作为模板参数传递给基类模板。
典型用途
1. 静态多态(替代虚函数)
template <typename Derived> class Animal { public: void Speak() { static_cast<Derived*>(this)->ImplementSpeak(); } }; class Cat : public Animal<Cat> { public: void ImplementSpeak() { std::cout << "Meow\n"; } }; class Dog : public Animal<Dog> { public: void ImplementSpeak() { std::cout << "Woof\n"; } }; // 使用 Animal<Cat> cat; cat.Speak(); // 输出 "Meow"(编译时绑定)
2. 计数器模式(统计实例数量)
template <typename T> class Counter { public: static int count; Counter() { ++count; } ~Counter() { --count; } }; template <typename T> int Counter<T>::count = 0; class Widget : public Counter<Widget> {}; // 每个Widget实例自动计数
3. 链式调用(Fluent Interface)
template <typename Derived> class Chainable { public: Derived& self() { return static_cast<Derived&>(*this); } Derived& SetX(int x) { /*...*/ return self(); } }; class Builder : public Chainable<Builder> { // 可链式调用:Builder().SetX(1).SetY(2) };
优点
- 性能:避免虚函数调用的运行时开销。
- 灵活性:基类可对派生类进行编译时定制。
- 代码复用:通用逻辑集中在基类中。
注意事项
- 类型安全:需确保模板参数确实是派生类(可通过
static_assert
验证)。 - 菱形继承:多重继承时可能引发问题。
- 可读性:代码可能对初学者较难理解。
与其他技术的对比
虚函数 | 运行时 | 较低 | 需要运行时动态绑定 |
CRTP | 编译时 | 高 | 需要静态多态或代码复用 |
概念/约束(C++20) | 编译时 | 高 | 类型约束和泛型编程 |
CRTP是C++模板元编程中的经典模式,广泛应用于库设计(如Boost.Iterator、Eigen等),适合需要高性能和编译时确定性的场景。