templates

由于想要对STL的具体实现有一个清楚的认识,因此在此先温习一下关于templates的相关知识。

模版的使用,将不同类型的具体实现交给了编译器去完成,从而实现了代码量的缩减,以达到清晰鲜明的目的。

如有个函数

   1: template <typename Type> // this is the template parameter declaration
   2: Type max(Type tX, Type tY)
   3: {
   4:     return (tX > tY) ? tX : tY;
   5: }

当你在编译程序时,编译器遇到相应的调用

   1: int nValue = max(3, 7); // calls max(int, int)

那么编译器将会对模版函数进行一次复制,并将类型改成相应的int类型,实现template instance.

   1: int max(int tX, int tY)
   2: {
   3:     return (tX > tY) ? tX : tY;
   4: }

在模版的使用中,除了具体类型可以外,还可以是表达式参数.

表达式参数可以是下面这些值:

1. 整型或是枚举

2. 对象的指针或是引用

3. 函数的指针或是引用

4. 类成员函数的指针或是引用

如:

   1: template <typename T, int nSize> // nSize is the expression parameter
   2: class Buffer
   3: {
   4: private:
   5:     // The expression parameter controls the size of the array
   6:     T m_atBuffer[nSize];
   7:  
   8: public:
   9:     T* GetBuffer() { return m_atBuffer; }
  10:  
  11:     T& operator[](int nIndex)
  12:     {
  13:         return m_atBuffer[nIndex];
  14:     }
  15: };
  16:  
  17: int main()
  18: {
  19:     // declare an integer buffer with room for 12 chars
  20:     Buffer<int, 12> cIntBuffer;
  21:  
  22:     // Fill it up in order, then print it backwards
  23:     for (int nCount=0; nCount < 12; nCount++)
  24:         cIntBuffer[nCount] = nCount;
  25:  
  26:     for (int nCount=11; nCount >= 0; nCount--)
  27:         std::cout << cIntBuffer[nCount] << " ";
  28:     std::cout << std::endl;
  29:  
  30:     // declare a char buffer with room for 31 chars
  31:     Buffer<char, 31> cCharBuffer;
  32:  
  33:     // strcpy a string into the buffer and print it
  34:     strcpy(cCharBuffer.GetBuffer(), "Hello there!");
  35:     std::cout << cCharBuffer.GetBuffer() << std::endl;
  36:  
  37:     return 0;
  38: }

模版中类型的特例化

看一下下面这个类:

   1: using namespace std;
   2:  
   3: template <typename T>
   4: class Storage
   5: {
   6: private:
   7:     T m_tValue;
   8: public:
   9:     Storage(T tValue)
  10:     {
  11:          m_tValue = tValue;
  12:     }
  13:  
  14:     ~Storage()
  15:     {
  16:     }
  17:  
  18:     void Print()
  19:     {
  20:         std::cout << m_tValue << std::endl;;
  21:     }
  22: };

如果采用下面的例子进行调用:

   1: int main()
   2: {
   3:     using namespace std;
   4:  
   5:     // Dynamically allocate a temporary string
   6:     char *strString = new char[40];
   7:  
   8:     // Ask user for their name
   9:     cout << "Enter your name: ";
  10:     cin >> strString;
  11:  
  12:     // Store the name
  13:     Storage<char*> strValue(strString);
  14:  
  15:     // Delete the temporary string
  16:     delete strString;
  17:  
  18:     // Print out our value
  19:     strValue.Print(); // This will print garbage
  20: }

来看一下此时类的构造:

   1: Storage<char*>::Storage(char* tValue)
   2: {
   3:      m_tValue = tValue;
   4: }

可以明显的发现m_tValue和strString指向同一块内存空间。

采用delete将strString删除后,使得m_tValue指向的内容也变成没有定义的了。而上面这个类在对于int类型的时候能够很好的实现。因此对于char*类型需要特殊对待。如下:

   1: Storage<char*>::Storage(char* tValue)
   2: {
   3:     // Allocate memory to hold the tValue string
   4:     m_tValue = new char[strlen(tValue)+1];
   5:     // Copy the actual tValue string into the m_tValue memory we just allocated
   6:     strcpy(m_tValue, tValue);
   7: }
   1: Storage<char*>::~Storage()
   2: {
   3:     delete[] m_tValue;
   4: }

整个类的特例化:

   1: template <typename T>
   2: class Storage8
   3: {
   4: private:
   5:     T m_tType[8];
   6:  
   7: public:
   8:     void Set(int nIndex, const T &tType)
   9:     {
  10:         m_tType[nIndex] = tType;
  11:     }
  12:  
  13:     const T& Get(int nIndex)
  14:     {
  15:         return m_tType[nIndex];
  16:     }
  17: };

上面这个类对于int的时候能够很好的实现,但是遇到bool时,由于bool的信息只用一个位就能够表示,而内存的最小存储单元是一个字节,因此采用上述的类存储bool的内存中有7/8是浪费的,因此采用另一种方式进行实现,构建一个新的类需要使用不用的变量名,使得使用的时候有一定的麻烦,因此采用了对整个类的特例化。

   1: template <> // the following is a template class with no templated parameters
   2: class Storage8<bool> // we're specializing Storage8 for bool
   3: {
   4: // What follows is just standard class implementation details
   5: private:
   6:     unsigned char m_tType;
   7:  
   8: public:
   9:     void Set(int nIndex, bool tType)
  10:     {
  11:         // Figure out which bit we're setting/unsetting
  12:         // This will put a 1 in the bit we're interested in turning on/off
  13:         unsigned char nMask = 1 << nIndex;
  14:  
  15:         if (tType)  // If we're setting a bit
  16:             m_tType |= nMask;  // Use bitwise-or to turn that bit on
  17:         else  // if we're turning a bit off
  18:             m_tType &= ~nMask;  // bitwise-and the inverse mask to turn that bit off
  19:     }
  20:  
  21:     bool Get(int nIndex)
  22:     {
  23:         // Figure out which bit we're getting
  24:         unsigned char nMask = 1 << nIndex;
  25:         // bitwise-and to get the value of the bit we're interested in
  26:         // Then implicit cast to boolean
  27:         return m_tType & nMask;
  28:     }
  29: };

posted on 2012-07-09 14:48 钟谢伟 阅读(997) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理


<2012年5月>
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789

导航

统计

常用链接

留言簿(1)

随笔档案

IT网站

My Friends

搜索

最新评论

阅读排行榜

评论排行榜