c++ CRTP模式的使用小結(jié)
CRTP(Curiously Recurring Template Pattern,奇異遞歸模板模式)是C++中一種高級的模板編程技術(shù),它通過將派生類作為基類的模板參數(shù)來實現(xiàn)編譯期多態(tài)。
1. CRTP的基本概念
基本結(jié)構(gòu)
// 基類模板
template<typename Derived>
class Base {
public:
void interface() {
// 將調(diào)用轉(zhuǎn)發(fā)給派生類的實現(xiàn)
static_cast<Derived*>(this)->implementation();
}
void static_interface() {
// 調(diào)用派生類的靜態(tài)方法
Derived::static_implementation();
}
};
// 派生類
class Derived : public Base<Derived> { // 關(guān)鍵:將自己作為模板參數(shù)
public:
void implementation() {
std::cout << "Derived implementation" << std::endl;
}
static void static_implementation() {
std::cout << "Derived static implementation" << std::endl;
}
};2. CRTP的核心原理
編譯期多態(tài)
template<typename Derived>
class Base {
public:
// 編譯期多態(tài):調(diào)用哪個implementation在編譯時確定
void foo() {
static_cast<Derived*>(this)->implementation();
}
// 可以添加默認實現(xiàn)
void bar() {
std::cout << "Base default implementation" << std::endl;
}
};3. CRTP的常見應(yīng)用
應(yīng)用1:靜態(tài)多態(tài)(編譯期多態(tài))
template<typename Derived>
class Shape {
public:
void draw() const {
// 編譯期調(diào)用派生類的具體實現(xiàn)
static_cast<const Derived*>(this)->draw_impl();
}
double area() const {
return static_cast<const Derived*>(this)->area_impl();
}
};
class Circle : public Shape<Circle> {
private:
double radius;
public:
Circle(double r) : radius(r) {}
// 實現(xiàn)基類期望的方法
void draw_impl() const {
std::cout << "Drawing Circle with radius " << radius << std::endl;
}
double area_impl() const {
return 3.14159 * radius * radius;
}
};
class Square : public Shape<Square> {
private:
double side;
public:
Square(double s) : side(s) {}
void draw_impl() const {
std::cout << "Drawing Square with side " << side << std::endl;
}
double area_impl() const {
return side * side;
}
};
// 使用
template<typename T>
void processShape(const Shape<T>& shape) {
shape.draw();
std::cout << "Area: " << shape.area() << std::endl;
}
int main() {
Circle circle(5.0);
Square square(4.0);
processShape(circle); // 編譯時生成Circle版本
processShape(square); // 編譯時生成Square版本
}應(yīng)用2:計數(shù)器模式
// 統(tǒng)計某個類創(chuàng)建的對象數(shù)量
template<typename T>
class Counter {
protected:
Counter() { ++count; }
Counter(const Counter&) { ++count; }
Counter(Counter&&) { ++count; }
~Counter() { --count; }
public:
static int getCount() { return count; }
private:
static int count;
};
// 靜態(tài)成員初始化
template<typename T>
int Counter<T>::count = 0;
// 使用
class MyClass1 : public Counter<MyClass1> {
// ...
};
class MyClass2 : public Counter<MyClass2> {
// ...
};
int main() {
MyClass1 a, b, c;
MyClass2 x, y;
std::cout << "MyClass1 count: " << MyClass1::getCount() << std::endl; // 3
std::cout << "MyClass2 count: " << MyClass2::getCount() << std::endl; // 2
// 注意:每個Counter實例都有自己的靜態(tài)count
}應(yīng)用3:多態(tài)拷貝(虛擬構(gòu)造函數(shù))
template<typename Derived>
class Cloneable {
public:
// 虛擬構(gòu)造函數(shù)模式
Derived* clone() const {
return new Derived(static_cast<const Derived&>(*this));
}
protected:
// 防止直接實例化
Cloneable() = default;
~Cloneable() = default;
};
class ConcreteClass : public Cloneable<ConcreteClass> {
public:
int value;
ConcreteClass(int v) : value(v) {}
// 自動獲得clone()方法
// 可以調(diào)用clone()來創(chuàng)建副本
};
int main() {
ConcreteClass obj1(42);
ConcreteClass* obj2 = obj1.clone();
std::cout << obj2->value << std::endl; // 42
delete obj2;
}應(yīng)用4:靜態(tài)接口檢查
// 混入模式:為類添加功能
template<typename Derived>
class Comparable {
public:
bool operator==(const Derived& other) const {
return !(static_cast<const Derived&>(*this) < other) &&
!(other < static_cast<const Derived&>(*this));
}
bool operator!=(const Derived& other) const {
return !(*this == other);
}
bool operator<=(const Derived& other) const {
return !(other < static_cast<const Derived&>(*this));
}
bool operator>=(const Derived& other) const {
return !(static_cast<const Derived&>(*this) < other);
}
bool operator>(const Derived& other) const {
return other < static_cast<const Derived&>(*this);
}
};
// 只需要實現(xiàn)operator<,自動獲得所有比較操作
class MyInt : public Comparable<MyInt> {
public:
int value;
MyInt(int v) : value(v) {}
bool operator<(const MyInt& other) const {
return value < other.value;
}
};
int main() {
MyInt a(10), b(20), c(10);
std::cout << std::boolalpha;
std::cout << (a < b) << std::endl; // true
std::cout << (a == b) << std::endl; // false
std::cout << (a == c) << std::endl; // true
std::cout << (a != b) << std::endl; // true
std::cout << (a <= c) << std::endl; // true
}4. CRTP的高級用法
訪問派生類成員
template<typename Derived>
class AccessDerived {
public:
void printInfo() {
Derived* derived = static_cast<Derived*>(this);
// 訪問派生類的protected成員
std::cout << "Value: " << derived->value << std::endl;
// 調(diào)用派生類的protected方法
derived->protectedMethod();
}
protected:
// 基類可以提供一些默認實現(xiàn)
virtual void protectedMethod() {
std::cout << "Base protected method" << std::endl;
}
};
class MyDerived : public AccessDerived<MyDerived> {
friend class AccessDerived<MyDerived>; // 允許基類訪問protected成員
protected:
int value = 42;
void protectedMethod() override {
std::cout << "Derived protected method" << std::endl;
}
};
多級CRTP
template<typename Derived>
class Level1 {
public:
void level1Method() {
std::cout << "Level1 calling: ";
static_cast<Derived*>(this)->implement();
}
};
template<typename Derived>
class Level2 : public Level1<Derived> {
public:
void level2Method() {
std::cout << "Level2 calling: ";
static_cast<Derived*>(this)->implement();
}
};
class FinalClass : public Level2<FinalClass> {
public:
void implement() {
std::cout << "FinalClass implementation" << std::endl;
}
};CRTP + 策略模式
// 策略接口
template<typename T>
class SerializationStrategy {
public:
std::string serialize(const T& obj) const {
return static_cast<const T*>(this)->serializeImpl();
}
};
// 具體策略
class JSONSerialization : public SerializationStrategy<JSONSerialization> {
public:
std::string serializeImpl() const {
return "{ \"type\": \"json\" }";
}
};
class XMLSerialization : public SerializationStrategy<XMLSerialization> {
public:
std::string serializeImpl() const {
return "<type>xml</type>";
}
};
// 使用策略的類
template<typename SerializationStrategy>
class DataProcessor {
private:
SerializationStrategy serializer;
public:
std::string process() {
return serializer.serialize(serializer);
}
};6. CRTP的最佳實踐
實踐1:使用類型檢查
template<typename Derived>
class Base {
// 編譯時檢查:確保Derived是從Base<Derived>派生的
static_assert(std::is_base_of<Base<Derived>, Derived>::value,
"Derived must inherit from Base<Derived>");
// C++17的更簡潔寫法
static_assert(std::is_base_of_v<Base, Derived>);
};實踐2:保護構(gòu)造函數(shù)
template<typename Derived>
class Base {
protected:
// 防止直接實例化Base
Base() = default;
~Base() = default;
// 防止在堆上創(chuàng)建Base
void* operator new(std::size_t) = delete;
void operator delete(void*) = delete;
};實踐3:使用CRTP實現(xiàn)Mixin
// Mixin:為類添加功能
template<template<typename> class... Mixins>
class MixedClass : public Mixins<MixedClass<Mixins...>>... {
// 繼承多個Mixin
};
// 定義Mixin
template<typename Derived>
class Printable {
public:
void print() const {
std::cout << "Printing..." << std::endl;
}
};
template<typename Derived>
class Serializable {
public:
std::string serialize() const {
return "Serialized";
}
};
// 使用
using MyClass = MixedClass<Printable, Serializable>;7. CRTP在實際項目中的應(yīng)用
示例:數(shù)學(xué)向量庫
template<typename Derived, typename T>
class VectorExpression {
public:
size_t size() const {
return static_cast<const Derived*>(this)->size();
}
T operator[](size_t i) const {
return static_cast<const Derived*>(this)->operator[](i);
}
// 延遲計算:表達式模板
Derived& operator+=(const VectorExpression& other) {
Derived& self = *static_cast<Derived*>(this);
for (size_t i = 0; i < size(); ++i) {
self[i] += other[i];
}
return self;
}
};
template<typename T>
class Vector : public VectorExpression<Vector<T>, T> {
private:
std::vector<T> data;
public:
Vector(size_t n, T val = T{}) : data(n, val) {}
size_t size() const { return data.size(); }
T operator[](size_t i) const { return data[i]; }
T& operator[](size_t i) { return data[i]; }
// 允許從任何VectorExpression構(gòu)造
template<typename E>
Vector(const VectorExpression<E, T>& expr) : data(expr.size()) {
for (size_t i = 0; i < expr.size(); ++i) {
data[i] = expr[i];
}
}
};8. CRTP的局限性
- 編譯時綁定:不能在運行時改變行為
- 代碼膨脹:每個模板實例都會生成新代碼
- 復(fù)雜的錯誤信息:模板錯誤信息難以理解
- 無法處理異質(zhì)集合:需要知道具體類型
- 循環(huán)依賴:基類需要知道派生類的完整定義
9. 何時使用CRTP
適合使用CRTP的情況:
- 需要靜態(tài)多態(tài)(性能關(guān)鍵)
- 實現(xiàn)混入(Mixin)功能
- 編譯期策略選擇
- 為類族添加通用功能
- 表達式模板
不適合使用CRTP的情況:
- 需要運行時多態(tài)
- 類型在運行時確定
- 需要存儲異質(zhì)對象的容器
- 項目對二進制大小敏感
總結(jié)
CRTP是C++模板元編程中的強大工具,它通過編譯期多態(tài)提供了零開銷的抽象能力。雖然學(xué)習(xí)曲線較陡,但在性能敏感的場景下,CRTP可以替代虛函數(shù),提供更好的運行時性能。
記住CRTP的核心思想:基類通過static_cast將this指針轉(zhuǎn)換為派生類指針,從而調(diào)用派生類的方法,所有這一切都在編譯期完成。
到此這篇關(guān)于c++ CRTP模式的使用小結(jié)的文章就介紹到這了,更多相關(guān)c++ CRTP模式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言中結(jié)構(gòu)體(struct)的幾種初始化方法
相信大家都知道struct結(jié)構(gòu)體是C語言中非常重要的復(fù)合類型,初始化的方法很多,那么小編下面對這些方法進行總結(jié),便于自己和大家以后查閱,有需要的可以參考借鑒。2016-08-08
C++設(shè)計模式編程中Template Method模板方法模式的運用
這篇文章主要介紹了C++設(shè)計模式編程中Template Method模板方法模式的運用,講到了包括模板方法模式中的細分方法以及適用場景,需要的朋友可以參考下2016-03-03
仿現(xiàn)代C++智能指針實現(xiàn)引用計數(shù)
這篇文章主要為大家詳細介紹了如何仿現(xiàn)代C++智能指針實現(xiàn)引用計數(shù),文中的示例代碼講解詳細,具有一定的借鑒價值,有需要的小伙伴可以了解下2024-03-03

