CRTP — 静态多态与编译期继承
基本形式
template <typename Derived>
class Base {
public:
void interface() {
static_cast<Derived *>(this)->impl(); // 编译期绑定
}
};
class MyClass : public Base<MyClass> {
public:
void impl() { std::cout << "MyClass\n"; }
};
MyClass obj;
obj.interface(); // 无虚函数调用,编译期确定地址
核心:基类把自己”向下转型”为派生类,在编译期直接调用派生类方法。零运行时开销。
vs 虚函数的性能差异
// 虚函数:运行时查 vtable
class Animal {
public: virtual void speak() = 0;
};
void call(Animal &a) { a.speak(); } // 间接调用
// CRTP:编译期绑定 → 可内联
template <typename T>
void call(Base<T> &b) { b.interface(); } // 编译期确定调用地址
// 基准测试(100 万次调用)
// 虚函数: ~5ms(一次间接跳转)
// CRTP: ~0.5ms(编译器内联后可能直接消除函数调用)
混入 (Mixin) — 组合功能
// 给任意类加 operator==
template <typename Derived>
class Comparable {
friend bool operator==(const Derived &a, const Derived &b) {
return a.tie() == b.tie(); // 依赖派生类的 tie()
}
};
class Point : public Comparable<Point> {
int x, y;
public:
Point(int x, int y) : x(x), y(y) {}
auto tie() const { return std::tie(x, y); }
};
Point p1(1, 2), p2(1, 2);
p1 == p2; // ✅ true — Comparable 自动生成
常见应用
// ① enable_shared_from_this 就是 CRTP
class MyClass : public std::enable_shared_from_this<MyClass> {};
// ② std::ranges::view_interface 也是 CRTP
template <typename Derived>
class view_interface { /* 提供 front/back/empty/operator[] */ };
// ③ 计数器混入
template <typename Derived>
class Counter {
static inline int count = 0;
public:
Counter() { ++count; }
~Counter() { --count; }
static int instances() { return count; }
};
class MyWidget : public Counter<MyWidget> {};
编译期多态选择
| 虚函数 | CRTP | Concepts | |
|---|---|---|---|
| 运行时多态 | ✅ | ❌ | ❌ |
| 编译期内联 | ❌ | ✅ | ✅ |
| 基类指针统一存储 | ✅ | ❌ | ❌ |
| 可读性 | 高 | 中 | 高 |
| 二进制体积 | +vtable | 模板膨胀 | 模板膨胀 |
决策:需要运行时存 vector<Base *> → 虚函数。不需要运行时多态但想复用代码 → CRTP 或 Concepts。