天天看點

模闆類與類模闆

在C++中有好幾個這樣的術語,但是我們很多時候用的并不正确,幾乎是互相替換混淆使用。下面我想徹底辨清幾個術語,這樣就可以避免很多概念上的混淆和使用上的錯誤。 

這幾個詞是: 

函數指針——指針函數 

數組指針——指針數組 

類模闆——模闆類 

函數模闆——模闆函數 

最終在使用中,我們就可以讓它們實至名歸,名正言順。 

1.函數指針——指針函數 

函數指針的重點是指針。表示的是一個指針,它指向的是一個函數,例子: 

int   (*pf)(); 

指針函數的重點是函數。表示的是一個函數,它的傳回值是指針。例子: 

int*   fun(); 

2.數組指針——指針數組 

數組指針的重點是指針。表示的是一個指針,它指向的是一個數組,例子: 

int   (*pa)[8]; 

指針數組的重點是數組。表示的是一個數組,它包含的元素是指針。例子; 

int*   ap[8]; 

3.類模闆——模闆類(class   template——template   class) 

類模闆的重點是模闆。表示的是一個模闆,專門用于産生類的模子。例子: 

template   <typename   T> 

class   Vector 

            … 

}; 

使用這個Vector模闆就可以産生很多的class(類),Vector <int> 、Vector <char> 、Vector <   Vector <int>   > 、Vector <Shape*> ……。 

模闆類的重點是類。表示的是由一個模闆生成而來的類。例子: 

上面的Vector <int> 、Vector <char> 、……全是模闆類。 

這兩個詞很容易混淆,我看到很多文章都将其用錯,甚至一些英文文章也是這樣。将他們區分開是很重要的,你也就可以了解為什麼在定義模闆的頭檔案.h時,模闆的成員函數實作也必須寫在頭檔案.h中,而不能像普通的類(class)那樣,class的聲明(declaration)寫在.h檔案中,class的定義(definition)寫在.cpp檔案中。請參照Marshall   Cline的《C++   FAQ   Lite》中的[34]   Container   classes   and   templates中的[34.12]   Why   can 't   I   separate   the   definition   of   my   templates   class   from   it 's   declaration   and   put   it   inside   a   .cpp   file?   URL位址是http://www.parashift.com/c++-faq-lite/containers-and-templates.html#faq-34.12 

我将幾句關鍵的段落摘錄如下,英文很好了解: 

In   order   for   the   compiler   to   generate   the   code,   it   must   see   both   the   template   definition   (not   just   declaration)   and   the   specific   types/whatever   used   to   "fill   in "   the   template.   For   example,   if   you 're   trying   to   use   a   Foo <int> ,   the   compiler   must   see   both   the   Foo   template   and   the   fact   that   you 're   trying   to   make   a   specific   Foo <int> .   

Suppose   you   have   a   template   Foo   defined   like   this:   

  template <class   T> 

  class   Foo   { 

  public: 

      Foo(); 

      void   someMethod(T   x); 

  private: 

      T   x; 

  };   

Along   with   similar   definitions   for   the   member   functions:   

  Foo <T> ::Foo() 

  { 

      ... 

  } 

  void   Foo <T> ::someMethod(T   x) 

  }   

Now   suppose   you   have   some   code   in   file   Bar.cpp   that   uses   Foo <int> :   

  //   Bar.cpp 

  void   blah_blah_blah() 

      Foo <int>   f; 

      f.someMethod(5); 

Clearly   somebody   somewhere   is   going   to   have   to   use   the   "pattern "   for   the   constructor   definition   and   for   the   someMethod()   definition   and   instantiate   those   when   T   is   actually   int.   But   if   you   had   put   the   definition   of   the   constructor   and   someMethod()   into   file   Foo.cpp,   the   compiler   would   see   the   template   code   when   it   compiled   Foo.cpp   and   it   would   see   Foo <int>   when   it   compiled   Bar.cpp,   but   there   would   never   be   a   time   when   it   saw   both   the   template   code   and   Foo <int> .   So   by   rule   above,   it   could   never   generate   the   code   for   Foo <int> ::someMethod().   

關于一個預設模闆參數的例子: 

template   <typename   T   =   int> 

class   Array 

第一次我定義這個模闆并使用它的時候,是這樣用的: 

Array   books;//我認為有預設模闆參數,這就相當于Array <int>   books 

上面的用法是錯誤的,編譯不會通過,原因是Array不是一個類。正确的用法是Array <>   books; 

這裡Array <> 就是一個用于預設模闆參數的類模闆所生成的一個具體類。 

4.函數模闆——模闆函數(function   template——template   function) 

函數模闆的重點是模闆。表示的是一個模闆,專門用來生産函數。例子: 

void   fun(T   a) 

在運用的時候,可以顯式(explicitly)生産模闆函數,fun <int> 、fun <double> 、fun <Shape*> ……。 

也可以在使用的過程中由編譯器進行模闆參數推導,幫你隐式(implicitly)生成。 

fun(6);//隐式生成fun <int> 

fun(8.9);//隐式生成fun <double> 

fun(‘a’);//   隐式生成fun <char> 

Shape*   ps   =   new   Cirlcle; 

fun(ps);//隐式生成fun <Shape*> 

模闆函數的重點是函數。表示的是由一個模闆生成而來的函數。例子: 

上面顯式(explicitly)或者隐式(implicitly)生成的fun <int> 、fun <Shape*> ……都是模闆函數。 

關于模闆本身,是一個非常龐大的主題,要把它講清楚,需要的不是一篇文章,而是一本書,幸運的是,這本書已經有了:David   Vandevoorde,   Nicolai   M.   Josuttis寫的《C++   Templates:   The   Complete   Guide》。可惜在大陸買不到紙版,不過有一個電子版在網上流傳。 

模闆本身的使用是很受限制的,一般來說,它們就隻是一個産生類和函數的模子。除此之外,運用的領域非常少了,是以不可能有什麼模闆指針存在的,即指向模闆的指針,這是因為在C++中,模闆就是一個代碼的代碼生産工具,在最終的代碼中,根本就沒有模闆本身存在,隻有模闆具現出來的具體類和具體函數的代碼存在。 

但是類模闆(class   template)還可以作為模闆的模闆參數(template   template   parameter)使用,在Andrei   Alexandrescu的《Modern   C++   Design》中的基于政策的設計(Policy   based   Design)中大量的用到。 //暫時不了解有什麼用處

template <   typename   T,   template <typename   U>   class   Y> 

class   Foo 

從文章的讨論中,可以看到,名字是非常重要的,如果對名字的使用不恰當的話,會引起很多的麻煩和誤解。我們在實際的程式中各種辨別符的命名也是一門學問,為了清晰易懂,有時候還是需要付出一定的代價。 

最後提醒:在本文的幾個術語中,語言的重心在後面,前面的詞是作為形容詞使用的。

本文轉自 神迹難覓 51CTO部落格,原文連結:http://blog.51cto.com/ji123/1917930,如需轉載請自行聯系原作者

繼續閱讀