胡说八道

学而不思则罔,思而不学则殆

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 :: 管理 ::
    看到这个题目你可能会觉得奇怪,CRTP是The Curiously Recurring Template Pattern的缩写.

     我们先来看一个简单的例子:
     template <typename Derived> 
     class CuriousBase { 
         … 
     }; 

     class Curious : public CuriousBase<Curious> { 
         … 
     };//摘自<<C++ Templates: The Complete Guide>>
       //16.3 The Curiously Recurring Template Pattern (CRTP)

     如果是第一次看到,你可能会觉得奇怪(我也想了半天),这里不会形成递归吗?这里有两个地方可能会产生递归,首先是声明,其次是实现的时候.比如说下面的代码:
     template <typename Derived> 
     class CuriousBase 
     {
  public:
   CuriousBase()
   {
    new Derived;
   }
     }; 

     class Curious : public CuriousBase<Curious> 
     { 
  public:
   Curious()
   {
   }
     };
     
     如果你的程序中加入了这样的代码,恭喜你了,你中了我们的大奖--崩溃;

     你可能会问,即使我们能避免这样的递归,可是这样的结构有什么用呢?

     我们先假设有种情况,比如说你的项目里面可能有10000多个类,现在要求你每个类都要实现print()函数,负责将类型的大小输出到std::cout上面,你们的老板还发话了,用函数实现,因为将来这个操作可能需要变更,最可气的是他规定说最好是不要用全局函数.

     第一个念头是继承一个有函数print()的接口
     class IAblePrint
     {
     public:
  void print()
  {
   cout<<sizeof(*this)<<endl;
  }
     };
     可惜这样做的结果不是我们需要的,那么我们设这个函数成为虚函数,然后每个类实现自己的?老天,那里有10000多个类等着我们呢.虽然全局函数是个不错的解决方案,但是那个可恶的老板!

     直觉告诉我们,这些成员函数一定是要实现的,可是有没有办法让编译器来替我们完成这些无聊的工作呢?

     下面就该CRTP登场了
     template<typename T>
     class AblePrintSize
     {
     public:
  void print()
  {
   cout<<sizeof(T)<<endl;
  }
     };

     class Test1:public AblePrintSize<Test1>
     {
  int t;
     };

     class Test2:public AblePrintSize<Test2>
     {
  int t[2];
     };

     int main() 
     {
         Test1 hu1;
         Test2 hu2;

         hu1.print();
         hu2.print();
     }

     这里我们只是自己多写了一个template class就达到了我们的目标.上面的例子可能举的不是很好,下面有个比较好的例子,大家可以参考参考

 #include <stddef.h> 

 template <typename CountedType> 
 class ObjectCounter { 
   private: 
     static size_t count;    // number of existing objects 

   protected: 
     // default constructor 
     ObjectCounter() { 
         ++ObjectCounter<CountedType>::count; 
     } 

     // copy constructor 
     ObjectCounter (ObjectCounter<CountedType> const&) { 
         ++ObjectCounter<CountedType>::count; 
     } 

     // destructor 
     ~ObjectCounter() { 
         --ObjectCounter<CountedType>::count; 
     } 

   public: 
     // return number of existing objects: 
     static size_t live() { 
         return ObjectCounter<CountedType>::count; 
     } 
 }; 

 // initialize counter with zero 
 template <typename CountedType> 
 size_t ObjectCounter<CountedType>::count = 0; 

 /*If we want to count the number of live (that is, not yet destroyed) objects for a certain class type, it suffices to derive the class from the ObjectCounter template. For example, we can define and use a counted string class along the following lines:*/

 // inherit/testcounter.cpp 

 #include "objectcounter.hpp" 
 #include <iostream> 

 template <typename CharT> 
 class MyString : public ObjectCounter<MyString<CharT> > { 
   … 
 }; 

 int main() 
 { 
     MyString<char> s1, s2; 
     MyString<wchar_t> ws; 
     std::cout << "number of MyString<char>: " 
               << MyString<char>::live() << std::endl; 
     std::cout << "number of MyString<wchar_t>: " 
               << ws.live() << std::endl; 
 } 
 

posted on 2004-12-29 11:30  胡说八道  阅读(1306)  评论(1)    收藏  举报