C++奇异递归模板模式(CRTP)
·
前言
C++奇异递归模板模式 (Curiously Recurring Template Pattern, CRTP) 是一种模板编程技术,其特点是派生类将自身作为基类模板的模板实参,使基类能够以静态多态的方式使用派生类的特性和方法,从而实现编译期的多态和代码复用。其一般形式是这样:
template <typename T>
class Base {
};
class Derived : public Base<Derived> {
// Derived 作为 Base 模板实参,同时又派生自 Base
// 这样 Base 中可将 this 转换为 T 派生类型,访问其接口
};
CRTP在编译期间确定类型和行为,实现了静态多态性,减少了运行时开销,但是灵活性不如运行时多态,且模板调试起来也很麻烦。
应用场景
1.静态多态
通过基类接口调用派生类实现
template <typename Derived>
class Shape {
public:
void draw() {
static_cast<Derived *>(this)->drawImpl();
}
};
class Circle : public Shape<Circle> {
public:
void drawImpl() { }
};
C++23的Deducing This特性(显式this参数)可以简化CRTP代码,不再需要显式的将派生类作为模板实参
class Shape {
public:
// Deducing this
void draw(this auto& self) {
self.drawImpl();
}
};
class Circle : public Shape {
public:
void drawImpl() {}
};
2.mixin(功能注入)
mixin是一种代码复用模式,通过继承或组合将功能混入到某个类中,给类增加额外的行为或属性,行为可以参考Python接口装饰器
把可复用的功能模块注入类(has-a),而不是表达is-a关系
template <typename Derived>
class CountableMixin {
private:
// C++17 inline内联初始化静态变量
static inline int counter{ 0 };
public:
CountableMixin() { ++counter; }
~CountableMixin() { --counter; }
static int count() { return counter; }
};
class MyClass : public CountableMixin<MyClass> {
// 自动获得计数功能
};
template <typename T>
struct Comparable {
friend bool operator==(const T& a, const T& b) {
return a.compare(b) == 0;
}
friend bool operator>(const T& a, const T& b) {
return a.compare(b) > 0;
}
// ... ...
};
// 多继承混合多种能力
class MyInt : public Comparable<MyInt>, ... ... {
public:
MyInt(int v) : value(v) {}
// 定义一个compare自动获得一系列比较运算符重载
int compare(const MyInt& other) const {
return value - other.value;
}
private:
int value;
};
3.模板方法模式
模板方法模式是一种行为设计模式,在父类中定义算法骨架,将一些步骤的实现延迟到子类
template <typename T>
class Base {
public:
void algorithm() {
static_cast<T*>(this)->step2();
}
void step1() {}
};
class Derived : public Base<Derived> {
public:
void step2() {}
};
此外工厂模式、策略模式等许多经典模式也可以用CRTP实现
4.std::enable_shared_from_this
C++标准库模板类std::enable_shared_from_this允许对象安全地获取指向自身的shared_ptr,避免从原始指针创建多个shared_ptr导致重复释放。其原理就是内部维护了一个weak_ptr,构造shared_ptr的时候会初始化这个weak_ptr。
#include <memory>
#include <iostream>
struct MyItem : public std::enable_shared_from_this<MyItem>
{
int value;
std::shared_ptr<MyItem> getSharedPtr()
{
return shared_from_this();
}
};
int main()
{
auto s1 = std::make_shared<MyItem>();
auto s2 = s1->getSharedPtr();
s1->value = 3;
std::cout << "s2 value = " << s2->value << std::endl;
return 0;
}
更多推荐
所有评论(0)