文章目录
CRTP
运行时多态(动态多态)使用传统继承 + 虚函数,会引入 虚表(vtable),每次调用虚函数都要通过间接寻址,影响性能。
CRTP(Curiously Recurring Template Pattern),即奇异递归模板模式,是一种 C++ 编译期多态技术(静态多态)。它的核心思想是:派生类作为模板参数传递给基类,从而在编译期实现静态多态,避免了运行时的虚函数开销。同时保持接口的可复用性。
基本实现
普通虚函数实现(动态多态):
虚函数(动态多态):interface() 通过 vtable(虚表) 调用 implementation(),运行时解析,有额外的虚函数开销。
cpp
class Base {
public:
virtual void implementation() { std::cout << "Base\n"; }
void interface() { implementation(); }
virtual ~Base() = default;
};
class Derived : public Base {
public:
void implementation() override { std::cout << "Derived\n"; }
};
CRTP 实现(静态多态,消除虚表):
Base< Derived> 是一个 模板基类,但它的模板参数是派生类 Derived 自己。
interface() 里使用 static_cast<Derived*>(this)->implementation();,在编译期解析出正确的implementation(),避免了虚函数的开销。
Derived 继承自 Base< Derived> ,提供 implementation() 方法,实际执行时 直接调用派生类的方法。
cpp
#include <iostream>
// CRTP 基类
template <typename Derived>
class Base {
public:
void interface() {
// 调用派生类的方法
static_cast<Derived*>(this)->implementation();
}
};
// 具体派生类
class Derived : public Base<Derived> {
public:
void implementation() {
std::cout << "Derived::implementation()" << std::endl;
}
};
int main() {
Derived d;
d.interface(); // 调用 Derived::implementation()
}
CRTP 的应用
- 实现静态计数器
通过 CRTP 模板参数区分不同类的静态变量,保证 A 和 B 各自维护自己的计数。
cpp
template <typename T>
class Counter {
static int count;
public:
Counter() { ++count; }
~Counter() { --count; }
static int getCount() { return count; }
};
// 静态变量初始化
template <typename T> int Counter<T>::count = 0;
// 统计不同类对象的数量
class A : public Counter<A> {};
class B : public Counter<B> {};
int main() {
A a1, a2;
B b1;
std::cout << "A count: " << A::getCount() << "\n"; // 2
std::cout << "B count: " << B::getCount() << "\n"; // 1
}
- C++ 标准库 std::enable_shared_from_this< T> 采用了 CRTP,让 MyClass 能够安全地从 this 返回 shared_ptr< T>,避免对象 被错误地 delete 两次。
cpp
#include <iostream>
#include <memory>
class MyClass : public std::enable_shared_from_this<MyClass> {
public:
std::shared_ptr<MyClass> getShared() {
return shared_from_this();
}
};
int main() {
auto ptr = std::make_shared<MyClass>();
auto sharedPtr = ptr->getShared();
std::cout << "Reference count: " << sharedPtr.use_count() << "\n"; // 2
}
std::enable_shared_from_this 只是 管理 shared_ptr 生命周期,和 CRTP 静态多态无关。
std::unique_ptr< Base>,建议用传统继承 + 虚函数。
如果想使用CRTP 的静态多态,但又希望能存储不同的子类对象,可以使用 std::variant如下所示:
cpp
#include <variant>
template <typename Derived>
class Base {
public:
void interface() {
static_cast<Derived*>(this)->implementation();
}
};
class Derived : public Base<Derived> {
public:
void implementation() {
std::cout << "Derived implementation\n";
}
};
int main() {
std::variant<Derived> obj = Derived();
std::visit([](auto& derived) { derived.interface(); }, obj);
}
总结
CRTP(奇异递归模板模式) 是 静态多态 的一种实现方式。
优势:
避免虚函数开销,提高性能。
可以在基类中调用派生类的方法。
模板编程的基础,支持静态计数器、链式调用、策略模式等。
劣势:
代码可读性较低,不适合过于复杂的继承体系。
不支持运行时多态,无法用于 std::unique_ptr< Base>。