c++模板技術

轉自http://blog.csdn.net/ilovedrv/archive/2010/07/10/5725402.aspx

1 概述


   c++的模板技術是把雙刃劍,一方面,模板靈活強大,變換無窮,stl、boost給程序員展現了模板技術的匪夷所思;另一方面,模板又是c++中處理虛機制外最複雜的技術,初學者往往不知所云。本文簡單的總結了以下自己工作中遇到的幾個問題,希望能對讀者有所幫助。 

2 關鍵字 typename vs class

  在模板定義時的class和typename是沒有區別的,因爲最初發明模板時決定使用class以減少一個關鍵字,但後來發現還是不得不加上typename關鍵字,參見如下代碼: 

 

  1. template<class C>     
  2. void f(C & rc)     
  3. {     
  4.   typename C::iterator  i  =  rc.begin();     
  5.   //   ...     
  6. }    

 

       編譯器不知道C的定義,所以不知道C::iterator是什麼東西,此處必須有typename來告訴編譯器,而不能使用class關鍵字。在Windows的vc6環境下,typename可以省略,編譯器自動識別補全,但在Linux的gcc編譯時,提示需要添加typename。

 

3 靜態變量初始化

  在Windows和Linux下移植C++代碼,尤其是模板,十分頭疼,Windows下的VC對C++標準支持的不是很好,而且還對很多C++標準進行了修改和擴展,這給移植增加了更大困難,另外gcc不同版本之間也有區別。 

  以下代碼演示了多類型的靜態變量初始化。

  1. template  <typename T>  
  2. class Image  
  3. {  
  4.   public:  
  5.     static const int flag;   
  6.   // ...  
  7. };   
  8.   
  9. const int Image<int>::flag = 10;  
  10. const int Image<float>::flag = 15;  

 

     上面的代碼,在vc6和gcc 3.2.2下均能編譯通過,但在新版gcc4.2.3下出現編譯器內部錯誤,需要採用如下方式初始化:

  1. template <> const int Image<int>::flag = 10;  
  2. template <> const int Image<float>::flag = 15;  

 

4 模板之多態

  在c++中,實現類型多態有兩種方式:虛函數和模板。 一般情況下,開發者習慣使用虛函數機制,這種方式採用的是動態綁定技術,即程序只有在運行時才能獲得函數執行入口,所以需要由編譯器自動生成一張虛函數表;而模板方式採用的是靜態綁定,即在編譯階段就能獲取函數入口,這種多態實現比較少見。參見如下示例:

  1. #include <iostream>   
  2.   
  3. using namespace std;  
  4.   
  5. template <typename T>   
  6. class B1  
  7. {  
  8. public:   
  9.   void SayHi()   
  10.   {  
  11.     T* pT = static_cast<T*>(this);    
  12.     pT->PrintClassName();  
  13.   }  
  14.   
  15.   void PrintClassName() { cout << "This is B1" << endl ; }  
  16. };  
  17.    
  18. class D1 : public B1<D1>  
  19. {  
  20.   // No overridden functions at all  
  21. };  
  22.    
  23. class D2 : public B1<D2>  
  24. {  
  25. public:  
  26.   void PrintClassName() { cout << "This is D2" << endl ; }  
  27. };  
  28.    
  29. int main()  
  30. {  
  31.   D1 d1;  
  32.   D2 d2;  
  33.    
  34.   d1.SayHi();    // prints "This is B1"  
  35.   d2.SayHi();    // prints "This is D2"  
  36.    
  37.   return 0;  
  38. }  

 

class D1 : public B1<D1> 定義是合法的,因爲c++語法支持,即D1只是被部分定義,類名D1已經被列入遞歸繼承列表,是可以使用的。將類名作爲模板類的參數實現了編譯期間的虛函數調用機制。 


  上面static_cast<T*>(this)是關鍵所在,它根據函數調用時的特殊處理將指向B1類型的指針this指派爲D1或D2類型的指針,因爲模板代碼是在編譯其間生成的,所以只要編譯器生成正確的繼承列表,這樣指派就是安全的。這很像C++的多態(polymorphism),只是SayHi()方法不是虛函數。 


  在第一個函數調用,對象B1被指派爲D1,所以代碼被解釋成:

  1. void B1<D1>::SayHi()  
  2. {  
  3.   D1* pT = static_cast<D1*>(this);  
  4.    
  5.   pT->PrintClassName();  
  6. }  

     D2實現類似。採用這種方法的優勢:不需要虛函數表;靜態綁定,有利於程序優化。

發佈了216 篇原創文章 · 獲贊 11 · 訪問量 30萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章