资讯动态

c++ CRTP模式的使用小结

发布时间:2026/8/11 1:43:23 来源:尧图企业网站定制
CRTPCuriously Recurring Template Pattern奇异递归模板模式是C中一种高级的模板编程技术它通过将派生类作为基类的模板参数来实现编译期多态。1. CRTP的基本概念基本结构1234567891011121314151617181920212223242526// 基类模板templatetypenameDerivedclassBase {public:voidinterface() {// 将调用转发给派生类的实现static_castDerived*(this)-implementation();}voidstatic_interface() {// 调用派生类的静态方法Derived::static_implementation();}};// 派生类classDerived :publicBaseDerived {// 关键将自己作为模板参数public:voidimplementation() {std::cout Derived implementation std::endl;}staticvoidstatic_implementation() {std::cout Derived static implementation std::endl;}};2. CRTP的核心原理编译期多态12345678910111213templatetypenameDerivedclassBase {public:// 编译期多态调用哪个implementation在编译时确定voidfoo() {static_castDerived*(this)-implementation();}// 可以添加默认实现voidbar() {std::cout Base default implementation std::endl;}};3. CRTP的常见应用应用1静态多态编译期多态123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960templatetypenameDerivedclassShape {public:voiddraw()const{// 编译期调用派生类的具体实现static_castconstDerived*(this)-draw_impl();}doublearea()const{returnstatic_castconstDerived*(this)-area_impl();}};classCircle :publicShapeCircle {private:doubleradius;public:Circle(doubler) : radius(r) {}// 实现基类期望的方法voiddraw_impl()const{std::cout Drawing Circle with radius radius std::endl;}doublearea_impl()const{return3.14159 * radius * radius;}};classSquare :publicShapeSquare {private:doubleside;public:Square(doubles) : side(s) {}voiddraw_impl()const{std::cout Drawing Square with side side std::endl;}doublearea_impl()const{returnside * side;}};// 使用templatetypenameTvoidprocessShape(constShapeT shape) {shape.draw();std::cout Area: shape.area() std::endl;}intmain() {Circle circle(5.0);Square square(4.0);processShape(circle);// 编译时生成Circle版本processShape(square);// 编译时生成Square版本}应用2计数器模式12345678910111213141516171819202122232425262728293031323334353637// 统计某个类创建的对象数量templatetypenameTclassCounter {protected:Counter() { count; }Counter(constCounter) { count; }Counter(Counter) { count; }~Counter() { --count; }public:staticintgetCount() {returncount; }private:staticintcount;};// 静态成员初始化templatetypenameTintCounterT::count 0;// 使用classMyClass1 :publicCounterMyClass1 {// ...};classMyClass2 :publicCounterMyClass2 {// ...};intmain() {MyClass1 a, b, c;MyClass2 x, y;std::cout MyClass1 count: MyClass1::getCount() std::endl;// 3std::cout MyClass2 count: MyClass2::getCount() std::endl;// 2// 注意每个Counter实例都有自己的静态count}应用3多态拷贝虚拟构造函数1234567891011121314151617181920212223242526272829303132templatetypenameDerivedclassCloneable {public:// 虚拟构造函数模式Derived* clone()const{returnnewDerived(static_castconstDerived(*this));}protected:// 防止直接实例化Cloneable() default;~Cloneable() default;};classConcreteClass :publicCloneableConcreteClass {public:intvalue;ConcreteClass(intv) : value(v) {}// 自动获得clone()方法// 可以调用clone()来创建副本};intmain() {ConcreteClass obj1(42);ConcreteClass* obj2 obj1.clone();std::cout obj2-value std::endl;// 42deleteobj2;}应用4静态接口检查123456789101112131415161718192021222324252627282930313233343536373839404142434445464748// 混入模式为类添加功能templatetypenameDerivedclassComparable {public:booloperator(constDerived other)const{return!(static_castconstDerived(*this) other) !(other static_castconstDerived(*this));}booloperator!(constDerived other)const{return!(*this other);}booloperator(constDerived other)const{return!(other static_castconstDerived(*this));}booloperator(constDerived other)const{return!(static_castconstDerived(*this) other);}booloperator(constDerived other)const{returnother static_castconstDerived(*this);}};// 只需要实现operator自动获得所有比较操作classMyInt :publicComparableMyInt {public:intvalue;MyInt(intv) : value(v) {}booloperator(constMyInt other)const{returnvalue other.value;}};intmain() {MyInt a(10), b(20), c(10);std::cout std::boolalpha;std::cout (a b) std::endl;// truestd::cout (a b) std::endl;// falsestd::cout (a c) std::endl;// truestd::cout (a ! b) std::endl;// truestd::cout (a c) std::endl;// true}4. CRTP的高级用法访问派生类成员12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455templatetypenameDerivedclassAccessDerived {public:voidprintInfo() {Derived* derived static_castDerived*(this);// 访问派生类的protected成员std::cout Value: derived-value std::endl;// 调用派生类的protected方法derived-protectedMethod();}protected:// 基类可以提供一些默认实现virtualvoidprotectedMethod() {std::cout Base protected method std::endl;}};classMyDerived :publicAccessDerivedMyDerived {friendclassAccessDerivedMyDerived;// 允许基类访问protected成员protected:intvalue 42;voidprotectedMethod() override {std::cout Derived protected method std::endl;}};多级CRTPtemplatetypenameDerivedclassLevel1 {public:voidlevel1Method() {std::cout Level1 calling: ;static_castDerived*(this)-implement();}};templatetypenameDerivedclassLevel2 :publicLevel1Derived {public:voidlevel2Method() {std::cout Level2 calling: ;static_castDerived*(this)-implement();}};classFinalClass :publicLevel2FinalClass {public:voidimplement() {std::cout FinalClass implementation std::endl;}};CRTP 策略模式1234567891011121314151617181920212223242526272829303132333435// 策略接口templatetypenameTclassSerializationStrategy {public:std::string serialize(constT obj)const{returnstatic_castconstT*(this)-serializeImpl();}};// 具体策略classJSONSerialization :publicSerializationStrategyJSONSerialization {public:std::string serializeImpl()const{return{ \type\: \json\ };}};classXMLSerialization :publicSerializationStrategyXMLSerialization {public:std::string serializeImpl()const{returntypexml/type;}};// 使用策略的类templatetypenameSerializationStrategyclassDataProcessor {private:SerializationStrategy serializer;public:std::string process() {returnserializer.serialize(serializer);}};6. CRTP的最佳实践实践1使用类型检查123456789templatetypenameDerivedclassBase {// 编译时检查确保Derived是从BaseDerived派生的static_assert(std::is_base_ofBaseDerived, Derived::value,Derived must inherit from BaseDerived);// C17的更简洁写法static_assert(std::is_base_of_vBase, Derived);};实践2保护构造函数1234567891011templatetypenameDerivedclassBase {protected:// 防止直接实例化BaseBase() default;~Base() default;// 防止在堆上创建Basevoid* operatornew(std::size_t) delete;voidoperatordelete(void*) delete;};实践3使用CRTP实现Mixin12345678910111213141516171819202122232425// Mixin为类添加功能templatetemplatetypenameclass... MixinsclassMixedClass :publicMixinsMixedClassMixins...... {// 继承多个Mixin};// 定义MixintemplatetypenameDerivedclassPrintable {public:voidprint()const{std::cout Printing... std::endl;}};templatetypenameDerivedclassSerializable {public:std::string serialize()const{returnSerialized;}};// 使用usingMyClass MixedClassPrintable, Serializable;7. CRTP在实际项目中的应用示例数学向量库123456789101112131415161718192021222324252627282930313233343536373839404142templatetypenameDerived,typenameTclassVectorExpression {public:size_tsize()const{returnstatic_castconstDerived*(this)-size();}T operator[](size_ti)const{returnstatic_castconstDerived*(this)-operator[](i);}// 延迟计算表达式模板Derived operator(constVectorExpression other) {Derived self *static_castDerived*(this);for(size_ti 0; i size(); i) {self[i] other[i];}returnself;}};templatetypenameTclassVector :publicVectorExpressionVectorT, T {private:std::vectorT data;public:Vector(size_tn, T val T{}) : data(n, val) {}size_tsize()const{returndata.size(); }T operator[](size_ti)const{returndata[i]; }T operator[](size_ti) {returndata[i]; }// 允许从任何VectorExpression构造templatetypenameEVector(constVectorExpressionE, T expr) : data(expr.size()) {for(size_ti 0; i expr.size(); i) {data[i] expr[i];}}};8. CRTP的局限性编译时绑定不能在运行时改变行为代码膨胀每个模板实例都会生成新代码复杂的错误信息模板错误信息难以理解无法处理异质集合需要知道具体类型循环依赖基类需要知道派生类的完整定义9. 何时使用CRTP适合使用CRTP的情况需要静态多态性能关键实现混入Mixin功能编译期策略选择为类族添加通用功能表达式模板不适合使用CRTP的情况需要运行时多态类型在运行时确定需要存储异质对象的容器项目对二进制大小敏感总结CRTP是C模板元编程中的强大工具它通过编译期多态提供了零开销的抽象能力。虽然学习曲线较陡但在性能敏感的场景下CRTP可以替代虚函数提供更好的运行时性能。记住CRTP的核心思想基类通过static_cast将this指针转换为派生类指针从而调用派生类的方法所有这一切都在编译期完成。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价