C++惯用法:奇特的递归模板模式(Curiously Recurring Template Pattern,CRTP,Mixin-from-above)

来源:互联网 发布:dns 协议端口号为53 编辑:程序博客网 时间:2024/04/30 20:07
一、什么是CRTP
奇特的模板递归模式(Curiously Recurring Template Pattern)即将派生类本身作为模板参数传递给基类。
template<typename T>
class BaseT{};
class D : public BaseT<D>{};
类D是一个非依赖型基类,不是模板。
 
(1)被继承的类模板(BaseT)的模板参数(T)可以是模板参数
template<typename T>
class BaseT{};
 
template<typename T>
class D : public BaseT<D<T> >{};
 
(2)被继承的类模板(BaseT)的模板参数(T)可以是模板
typename<template<typename> class T>
class BaseT{};
 
template<typename T>
class D : public BaseT<D>{};
 
二、CRTP的一个简单应用就是记录某个类对象构造的总个数。

#include<stddef.h>
#include<iostream>

template<typename CountedType>
class ObjectCounter{
static size_t count;
protected:
ObjectCounter(){ ++ObjectCounter<CountedType>::count; } //声明为protected,防止生成对象,限定只能被继承
ObjectCounter(const ObjectCounter<CountedType>& ){ ++ObjectCounter<CountedType>::count; }
~ObjectCounter(){ --count; }

public:
static size_t getCount(){ return ObjectCounter<CountedType>::count; }//作为静态函数,类方法
};
template<typename CountedType>
size_t ObjectCounter<CountedType>::count = 0;

template<typename T>
class MyString : public ObjectCounter<MyString<T> >{}; //CRTP

 
int main()
{
    MyString<char> s1, s2;
    MyString<wchar_t> ws;
    std::cout << "MyString<char>:"<< MyString<char>::getCount()<< std::endl; //输出2
   std::cout << "MyString<wchar_t>:"<< MyString<wchar_t>::getCount() << std::endl; //输出1
}
 
编辑整理:Claruarius,转载请注明出处。



意图:

使用派生类作为模板参数特化基类。

 

与多态的区别:

多态是动态绑定(运行时绑定),CRTP是静态绑定(编译时绑定)

 

在实现多态时,需要重写虚函数,因而这是运行时绑定的操作。

然而如果想在编译期确定通过基类来得到派生类的行为,CRTP便是一种独佳选择,它是通过派生类覆盖基类成员函数来实现静态绑定的。

 

范式:

[cpp] view plaincopy
  1. class derived : public base<derived>  
  2. {  
  3.     // attributes and behaviors  
  4. }  

 

示例代码:

[c-sharp] view plaincopy
  1. template <class Derived>  
  2.   struct base  
  3.   {  
  4.       void interface()  
  5.       {  
  6.           // 转换为子类指针,编译期将绑定至子类方法  
  7.           static_cast<Derived*>(this)->implementation();  
  8.       }  
  9.    
  10.       static void static_interface()  
  11.       {  
  12.           // 编译期将绑定至子类方法  
  13.           Derived::static_implementation();  
  14.       }  
  15.    
  16.       // 下面两个方法,默认实现可以存在,或者应该被继承子类的相同方法覆盖  
  17.       void implementation();  
  18.       static void static_implementation();  
  19.   };  
  20.    
  21.   // The Curiously Recurring Template Pattern (CRTP)  
  22.   struct derived_1 : base<derived_1>  
  23.   {  
  24.       // 这里子类不实现,将使用父类的默认实现  
  25.       //void implementation();  
  26.    
  27.       // 此方法将覆盖父类的方法  
  28.       static void static_implementation();  
  29.   };  
  30.    
  31.   struct derived_2 : base<derived_2>  
  32.   {  
  33.       // 此方法将覆盖父类的方法  
  34.       void implementation();  
  35.    
  36.       // 这里子类不实现,将使用父类的默认实现  
  37.       //static void static_implementation();  
  38.   };  

 

缺点:

CRTP由于基类使用了模板,目前的编译器不支持模板类的导出,因而不能使用导出接口。

 

其它使用领域:

在数值计算中,往往要对不同的模型使用不同的计算方法(如矩阵),一般使用继承提供统一接口(如operator运算符),但又希望不损失效率。这时便又可取CRTP惯用法,子类的operator实现将覆盖基类的operator实现,并可以编译期静态绑定至子类的方法。



0 0
原创粉丝点击