奇异递归模板

本文介绍了CRTP(Curiously Recurring Template Pattern)模板,这是一种实现静态多态的技术,用于在编译时实现多态并提高性能。通过将基类模板设置为子类,CRTP允许基类在编译时访问子类信息。文章讲解了CRTP的关键点,包括子类信息注入、静态类型转换和编译时多态的析构。代码示例展示了如何使用CRTP创建一个处理接口,并在不同场景下调用。最后,文章提到CRTP通常用于性能敏感的环境,可以提供30%-40%的性能提升,但在一般开发中,多态的可读性更好。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

奇异递归模板

CRTP通过将基类模板设置为子类,从而实现静态多态(编译器多态),或者扩展接口(委托实现)
要点解析:
1:class Sub : public Base<Sub>,通过模板参数,将子类信息注入到基类,从而实现基类中提前获取子类类型信息
2:static_cast<T*>(this),将基类指针转为模板子类T的指针
3:Base类型是不完整类,不能直接用Sub参与内存布局,但可以在类接口中使用(实际发生调用的时候,模板在编译的时候就辨析了)
4:删除对象,也要使用编译时多态进行删除,避免直接delete
5:模板CRTP基类不能有virtual(因为要编译时多态)

一般用在性能要求非常苛刻的环境中,评测预估性能提升30~40%。 对于一般开发,使用多态更方便阅读。

代码实现

#include <iostream>
#include <string>
#include <sstream>
#include <memory>
#include <vector>
using namespace std;

// 基类参数T包含了子类编译时信息
template <typename T> //T一定要子类才能crtp,子类信息注入到父类
class Base {
public:
    void process() { 
      sub()->process_imp(); //编译时分发
    }

    //如果不实现,类似纯虚函数
    void process_imp() { 
      cout<<"Base::process()"<<endl;
    }

    //将基类指针转型为子类T的指针,static_cast编译多态,dynamic_cast要求虚函数
    T* sub() { return static_cast<T*>(this); }	//this就是main中的ps1,转型为子类

    ~Base()	//也可以改为virtual,也会析构正常,但会产生虚函数表,背离了编译时多态
    {
      //delete sub(); // static_cast<T*>(this);	//会死循环,子类调用父类,父类又要调用子类
      cout<<"~Base()"<<endl;	//必须先析构子类,再析构父类
    }

    void destroy() 
    { 
        delete sub();// static_cast<T*>(this); 
    }

//	T b; //不能,T还是不完整类型,不能参与内存布局
//只能用指针,因为语义上,Base中包含一个sub,而sub又继承base,会导致死循环
};

class Sub1 : public Base<Sub1> {
public:
    ~Sub1()
    {
      cout<<"~Sub1"<<endl;
    }

    void process_imp() { 
      cout<<"Sub1::process()"<<endl;
    }
};

template <typename T>
void invoke(Base<T>* pb)
{
  pb->process();
}

int main()
{
  Base<Sub1> *ps1=new Sub1();	//声明基类,效果类似虚函数,只是为编译时多态
  ps1->process();// process(ps1)

  invoke(ps1);
  //delete ps1;	//不能正确删除,因为是编译时删除,只是删除了基类
  ps1->destroy();
}

代码执行

kongcb@tcu-pc:~/testcode/template$ g++ crtp_interface.cpp -o crtp_interface
kongcb@tcu-pc:~/testcode/template$ ./crtp_interface
Sub1::process()
Sub1::process()
~Sub1
~Base()
<think>好的,我现在需要帮助用户理解奇异递归模板模式(CRTP)的定义、实现和示例。用户已经提供了三个引用资料,我需要结合这些内容来组织回答。 首先,CRTP的定义。根据引用[1]和[2],CRTP是一种C++设计模式,基类模板将派生类作为模板参数。基类通过模板参数访问派生类的成员,实现静态多态。需要明确说明基类和派生类的关系,特别是自引用的特点。 接下来是实现部分。引用[3]中的代码示例展示了基类模板如何接受派生类作为参数,并在基类中使用static_cast将this转换为派生类指针。这样基类可以调用派生类的方法,或者派生类重写基类的函数。需要分步骤说明基类模板的定义、派生类的继承方式,以及如何通过static_cast实现类型转换。同时,引用[1]提到的链式调用可能也是实现的一个方面,可以结合说明。 然后是示例部分。需要提供一个简单的代码示例,展示CRTP的具体应用。比如基类有某个方法,派生类实现后,基类通过模板参数调用派生类的方法。比如计数器模式,基类记录对象数量,派生类继承并自动更新计数。或者像引用[3]中的print函数,派生类重写基类的print方法,基类调用时显示不同信息。 另外,需要注意用户提到的行内公式和独立公式的格式要求。不过目前看来,CRTP的内容可能不涉及数学公式,但如果有涉及的地方需要正确使用LaTeX格式。 用户还要求生成相关问题,我需要考虑CRTP的常见应用场景、优缺点、与其他模式的区别,以及实际项目中的使用案例等。 现在检查引用内容是否准确。引用[1]提到基类返回派生类引用,引用[2]说明基类模板接受派生类作为参数,引用[3]给出了具体的代码结构。需要确保这些内容在回答中被正确引用,并在适当的位置添加引用标识。 可能需要注意术语的一致性,比如CRTP的不同称呼,确保使用用户提供的资料中的术语。同时,解释CRTP如何实现静态多态,与动态多态的区别,以及其优势(如性能提升,编译时多态)。 最后,结构要清晰,分点回答定义、实现、示例,每个部分简明扼要,代码示例正确,并符合用户的格式要求。</think>### 奇异递归模板模式(CRTP)解析 #### 1. **定义** 奇异递归模板模式(Curiously Recurring Template Pattern, CRTP)是C++中一种**静态多态**设计模式,其核心思想是**基类模板以派生类作为模板参数**,从而实现基类对派生类成员的直接访问[^2]。 这种模式通过模板的自引用特性(基类依赖派生类的类型)实现编译时的多态行为,避免运行时虚函数开销[^3]。 --- #### 2. **实现** CRTP的实现分为以下关键步骤: 1. **基类模板定义**:基类模板接受一个类型参数`Derived`(实际为派生类)。 2. **派生类继承**:派生类通过`public Base<Derived>`递归继承基类模板。 3. **类型转换**:基类通过`static_cast<Derived*>(this)`将自身指针转换为派生类指针,调用派生类方法。 **代码示例(基础结构)**: ```cpp template <typename Derived> class Base { public: void interface() { static_cast<Derived*>(this)->implementation(); // 调用派生类方法 } }; class Derived : public Base<Derived> { public: void implementation() { /* 具体实现 */ } }; ``` --- #### 3. **示例:对象计数器** 以下示例通过CRTP统计某个类的实例数量: ```cpp template <typename T> class Counter { public: static int count; Counter() { ++count; } ~Counter() { --count; } static int getCount() { return count; } }; template <typename T> int Counter<T>::count = 0; // 派生类继承基类模板并将自身作为参数传递 class MyClass : public Counter<MyClass> { /* 类定义 */ }; // 使用 MyClass obj1, obj2; std::cout << MyClass::getCount(); // 输出2 ``` 此例中,`Counter`基类通过模板参数`T`区分不同派生类的计数器,实现编译时类型隔离。 --- #### 4. **核心优势** - **零运行时开销**:静态多态无需虚函数表(vtable)。 - **编译时多态**:类型检查和优化在编译阶段完成。 - **链式调用支持**:基类方法返回派生类引用,支持链式语法(如`obj.func1().func2()`)[^1]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

超级波

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值