乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      C++中的類模板詳細(xì)講述

       lchjczw 2013-05-14

      一、類模板定義及實(shí)例化

      . 定義一個(gè)類模板:

      復(fù)制代碼
      1 template<class 模板參數(shù)表>
      2
      3 class 類名{
      4
      5 // 類定義......
      6
      7 };
      復(fù)制代碼

       

      其中,template 是聲明類模板的關(guān)鍵字,表示聲明一個(gè)模板,模板參數(shù)可以是一個(gè),也可以是多個(gè),可以是類型參數(shù) ,也可以是非類型參數(shù)。類型參數(shù)由關(guān)鍵字class或typename及其后面的標(biāo)識(shí)符構(gòu)成。非類型參數(shù)由一個(gè)普通參數(shù)構(gòu)成,代表模板定義中的一個(gè)常量。

      例:

      1 template<class type,int width>
      2
      3 //type為類型參數(shù),width為非類型參數(shù)
      4
      5 class Graphics;

      注意:

      (1)如果在全局域中聲明了與模板參數(shù)同名的變量,則該變量被隱藏掉。

      (2)模板參數(shù)名不能被當(dāng)作類模板定義中類成員的名字。

      (3)同一個(gè)模板參數(shù)名在模板參數(shù)表中只能出現(xiàn)一次。

      (4)在不同的類模板或聲明中,模板參數(shù)名可以被重復(fù)使用。

      復(fù)制代碼
       1 typedef string type;
      2
      3 template<class type,int width>
      4
      5 class Graphics
      6
      7 {
      8
      9 type node;//node不是string類型
      10
      11 typedef double type;//錯(cuò)誤:成員名不能與模板參數(shù)type同名
      12
      13 };
      14
      15 template<class type,class type>//錯(cuò)誤:重復(fù)使用名為type的參數(shù)
      16
      17 class Rect;
      18
      19 template<class type> //參數(shù)名”type”在不同模板間可以重復(fù)使用
      20
      21 class Round;
      復(fù)制代碼


      (5)
      在類模板的前向聲明和定義中,模板參數(shù)的名字可以不同。

      復(fù)制代碼
       1 // 所有三個(gè) Image 聲明都引用同一個(gè)類模板的聲明
      2
      3 template <class T> class Image;
      4
      5 template <class U> class Image;
      6
      7 // 模板的真正定義
      8
      9 template <class Type>
      10
      11 class Image { //模板定義中只能引用名字”Type”,不能引用名字”T”和”U” };
      復(fù)制代碼


      (6)
      類模板參數(shù)可以有缺省實(shí)參,給參數(shù)提供缺省實(shí)參的順序是先右后左。

      View Code


      (7)
      類模板名可以被用作一個(gè)類型指示符。當(dāng)一個(gè)類模板名被用作另一個(gè)模板定義中的類型指示符時(shí),必須指定完整的實(shí)參表

      View Code


      2.
      類模板實(shí)例化

      定義:從通用的類模板定義中生成類的過程稱為模板實(shí)例化。

      例:Graphics<int> gi;

      類模板什么時(shí)候會(huì)被實(shí)例化呢?

      當(dāng)使用了類模板實(shí)例的名字,并且上下文環(huán)境要求存在類的定義時(shí)。

      對(duì)象類型是一個(gè)類模板實(shí)例,當(dāng)對(duì)象被定義時(shí)。此點(diǎn)被稱作類的實(shí)例化點(diǎn)。

      一個(gè)指針或引用指向一個(gè)類模板實(shí)例,當(dāng)檢查這個(gè)指針或引用所指的對(duì)象時(shí)。

      例:

      復(fù)制代碼
       1 template<class Type>
      2
      3 class Graphics{};
      4
      5 void f1(Graphics<char>);// 僅是一個(gè)函數(shù)聲明,不需實(shí)例化
      6
      7 class Rect
      8
      9 {
      10
      11   Graphics<double>& rsd;// 聲明一個(gè)類模板引用,不需實(shí)例化
      12
      13   Graphics<int> si;// si是一個(gè)Graphics類型的對(duì)象,需要實(shí)例化類模板
      14
      15 }
      16
      17 int main(){
      18
      19   Graphcis<char>* sc;// 僅聲明一個(gè)類模板指針,不需實(shí)例化
      20
      21   f1(*sc);//需要實(shí)例化,因?yàn)閭鬟f給函數(shù)f1的是一個(gè)Graphics<int>對(duì)象。
      22
      23   int iobj=sizeof(Graphics<string>);//需要實(shí)例化,因?yàn)閟izeof會(huì)計(jì)算Graphics<string>對(duì)象的大小,為了計(jì)算大小,編譯器必須根據(jù)類模板定義產(chǎn)生該類型。
      24
      25 }
      復(fù)制代碼


      3.
      非類型參數(shù)的模板實(shí)參

      要點(diǎn)

      綁定給非類型參數(shù)的表達(dá)式必須是一個(gè)常量表達(dá)式。

      從模板實(shí)參到非類型模板參數(shù)的類型之間允許進(jìn)行一些轉(zhuǎn)換。包括左值轉(zhuǎn)換、限定修飾轉(zhuǎn)換、提升、整值轉(zhuǎn)換。

      可以被用于非類型模板參數(shù)的模板實(shí)參的種類有一些限制。

      例:

      復(fù)制代碼
       1 Template<int* ptr> class Graphics{…….};
      2
      3 Template<class Type,int size> class Rect{……..};
      4
      5 const int size=1024;
      6
      7 Graphics<&size> bp1;//錯(cuò)誤:從const int*->int*是錯(cuò)誤的。
      8
      9 Graphics<0> bp2;//錯(cuò)誤不能通過隱式轉(zhuǎn)換把0轉(zhuǎn)換成指針值
      10
      11 const double db=3.1415;
      12
      13 Rect<double,db> fa1;//錯(cuò)誤:不能將const double轉(zhuǎn)換成int.
      14
      15 unsigned int fasize=255;
      16
      17 Rect<String, fasize> fa2;//錯(cuò)誤:非類型參數(shù)的實(shí)參必須是常量表達(dá)式,將unsigned改為const就正確。
      18
      19 Int arr[10];
      20
      21 Graphics<arr> gp;//正確
      復(fù)制代碼

       

      二、類模板的成員函數(shù)

      要點(diǎn):

      類模板的成員函數(shù)可以在類模板的定義中定義(inline函數(shù)),也可以在類模板定義之外定義(此時(shí)成員函數(shù)定義前面必須加上template及模板參數(shù))。

      類模板成員函數(shù)本身也是一個(gè)模板,類模板被實(shí)例化時(shí)它并不自動(dòng)被實(shí)例化,只有當(dāng)它被調(diào)用或取地址,才被實(shí)例化。

      復(fù)制代碼
       1 template<class type>
      2
      3 Class Graphics{
      4
      5 Graphics(){…}//成員函數(shù)定義在類模板的定義中
      6
      7 void out();
      8
      9 };
      10
      11 template<class type>//成員函數(shù)定義在類模板定義之外
      12
      13 void Graphics<type>::out(){…}
      復(fù)制代碼

      三、類模板的友元聲明

      類模板中可以有三種友元聲明:

      .非模板友元類或友元函數(shù)

      復(fù)制代碼
       1 class Graphics{void out();};
      2
      3 Template<class T>
      4
      5 Class Rect{
      6
      7 friend class Graphics;//類Graphics、函數(shù)
      8
      9 friend void create();// create、 out是類模板
      10
      11 friend void Graphics::out();// Rect所有實(shí)例的友元
      12
      13 };
      復(fù)制代碼

      2、綁定的友元類模板或函數(shù)模板。

      3、非綁定的友元類模板或函數(shù)模板。

      第二種聲明表示類模板的實(shí)例和它的友元之間是一種一對(duì)一的映射關(guān)系。

      如圖:

      第三種聲明表示類模板的實(shí)例和它的友元之間是一種一對(duì)多的映射關(guān)系。

      如圖:

      例:綁定的友元模板

      復(fù)制代碼
       1 template<class type>
      2
      3 void create(Graphics<type>);
      4
      5 template<class type>
      6
      7 class Graphics{
      8
      9 friend void create<type>(Graphics<type>);
      10
      11 };
      復(fù)制代碼


      例:非綁定的友元模板

      復(fù)制代碼
      1 template<class type>
      2
      3 class Graphics{
      4
      5 template<class T>
      6
      7 friend void create(Graphics<T>);
      8
      9 };
      復(fù)制代碼


      注意
      當(dāng)把非模板類或函數(shù)聲明為類模板友元時(shí),它們不必在全局域中被聲明或定義,但將一個(gè)類的成員聲明為類模板友元,該類必須已經(jīng)被定義,另外在聲明綁定的友元類模板或函數(shù)模板時(shí),該模板也必須先聲明。

      例:

      復(fù)制代碼
       1 template <class T>
      2
      3 class A {
      4
      5 private:
      6
      7 friend class B<T>; //錯(cuò)誤:類B必須先聲明
      8
      9 };
      10
      11 template <class T>
      12
      13 class B{};
      復(fù)制代碼

      四、類模板的靜態(tài)數(shù)據(jù)成員、嵌套類型

      .類模板的靜態(tài)數(shù)據(jù)成員

      要點(diǎn):

      靜態(tài)數(shù)據(jù)成員的模板定義必須出現(xiàn)在類模板定義之外。

      類模板靜態(tài)數(shù)據(jù)成員本身就是一個(gè)模板,它的定義不會(huì)引起內(nèi)存被分配,只有對(duì)其實(shí)例化才會(huì)分配內(nèi)存。

      當(dāng)程序使用靜態(tài)數(shù)據(jù)成員時(shí),它被實(shí)例化,每個(gè)靜態(tài)成員實(shí)例都與一個(gè)類模板實(shí)例相對(duì)應(yīng),靜態(tài)成員的實(shí)例引用要通過一個(gè)類模板實(shí)例。

      例:

      復(fù)制代碼
       1 template<class type>
      2
      3 class Graphics{
      4
      5 static Graphics *next;
      6
      7 static const type item;
      8
      9 };
      10
      11 template<class type>
      12
      13 Graphics<type> * Graphics<type>::next=0;
      14
      15 template<class type>
      16
      17 type Graphics<type>::item=NULL;
      18
      19 //靜態(tài)成員定義分為兩部分:前一部分是類型,比如Graphics<type>*,后一部分是名稱和值,比如Graphics<type>::next=0;
      復(fù)制代碼

      2.類模板的嵌套類型

      要點(diǎn)

      在類模板中允許再嵌入模板,因此類模板的嵌套類也是一個(gè)模板,它可以使用外圍類模板的模板參數(shù)。

      當(dāng)外圍類模板被實(shí)例化時(shí),它不會(huì)自動(dòng)被實(shí)例化,只有當(dāng)上下文需要它的完整類類型時(shí),它才會(huì)被實(shí)例化。

      公有嵌套類型可以被用在類定義之外,這時(shí)它的名字前必須加上類模板實(shí)例的名字。

      例:

      復(fù)制代碼
       1 template<class type>
      2
      3 class Graphics{
      4
      5 public:
      6
      7 template<class T>
      8
      9 class Rect{void out(type a,T b);};
      10
      11 };
      12
      13 Graphics<int>::Rect<double> node;
      14
      15 //引用公有嵌套類型必須加上類模板實(shí)例名字
      復(fù)制代碼


      五、成員模板

      定義:成員定義前加上template及模板參數(shù)表。

      要點(diǎn):

      在一個(gè)類模板中定義一個(gè)成員模板,意味著該類模板的一個(gè)實(shí)例包含了可能無限多個(gè)嵌套類和無限多個(gè)成員函數(shù).

      只有當(dāng)成員模板被使用時(shí),它才被實(shí)例化.

      成員模板可以定義在其外圍類或類模板定義之外.

      例:

      復(fù)制代碼
       1 template<class type>
      2
      3 class Graphics<type>{
      4
      5 public:template<class T>
      6
      7 class Rect{void out(type a,T b);};};
      8
      9 template<class Gtype> template<class TT>
      10
      11 void Graphics<Gtype>::Rect<TT>::out(Gtype a,TT b){}//成員模板被定義在類模板定義之外(要根上完整模板實(shí)參)
      12
      13 Graphics<int>的實(shí)例可能包括下列嵌套類型:
      14
      15 Graphics<int>::Rect<double>
      16
      17 Graphics<int>::Rect<string>
      復(fù)制代碼


      注意:類模板參數(shù)不一定與類模板定義中指定的名字相同。

       

      六、類模板的編譯模式

      1.包含編譯模式

      這種編譯模式下,類模板的成員函數(shù)和靜態(tài)成員的定義必須被包含在“要將它們實(shí)例化”的所有文件中,如果一個(gè)成員函數(shù)被定義在類模板定義之外,那么這些定義應(yīng)該被放在含有該類模板定義的頭文件中。

      2.分離編譯模式

      這種模式下,類模板定義和其inline成員函數(shù)定義被放在頭文件中,而非inline成員函數(shù)和靜態(tài)數(shù)據(jù)成員被放在程序文本文件中。

      例:

      復(fù)制代碼
       1 //------Graphics.h---------
      2
      3 export template<class type>
      4
      5 Class Graphics
      6
      7 {void Setup(const type &);};
      8
      9 //-------Graphics.c------------
      10
      11 #include “Graphics.h”
      12
      13 Template <class type>
      14
      15 Void Graphics<type>::Setup(const type &){…}
      16
      17 //------user.c-----
      18
      19 #include “Graphics.h”
      20
      21 Void main()
      22
      23 {Graphics<int> *pg=new Graphics<int>;
      24
      25 Int ival=1;
      26
      27 //Graphics<int>::Setup(const int &)的實(shí)例(下有注解)
      28
      29 Pg->Setup(ival);
      30
      31 }
      復(fù)制代碼


      Setup的成員定義在User.c中不可見,但在這個(gè)文件中仍可調(diào)用模板實(shí)例Graphics<int>::Setup(const int &)。為實(shí)現(xiàn)這一點(diǎn),須將類模聲明為可導(dǎo)出的:當(dāng)它的成員函數(shù)實(shí)例或靜態(tài)數(shù)據(jù)成員實(shí)例被使用時(shí),編譯器只要求模板的定義,它的聲明方式是在關(guān)鍵字template前加關(guān)鍵字export

      .顯式實(shí)例聲明

      當(dāng)使用包含編譯模式時(shí),類模板成員的定義被包含在使用其實(shí)例的所有程序文本文件中,何時(shí)何地編譯器實(shí)例化類模板成員的定義,我們并不能精確地知曉,為解決這個(gè)問題,標(biāo)準(zhǔn)C++提供了顯式實(shí)例聲明:關(guān)鍵字template后面跟著關(guān)鍵字class以及類模板實(shí)例的名字。

      例:

      1 #include “Graphics.h”
      2
      3 Template class Graphics<int>;//顯式實(shí)例聲明


      顯式實(shí)例化類模板時(shí),它的所有成員也被顯式實(shí)例化。

       

      七、類模板的特化及部分特化

      1.類模板的特化

      先看下面的例子:

      復(fù)制代碼
      1 Template<class type>
      2
      3 Class Graphics{
      4
      5 Public:void out(type figure){…}};
      6
      7 Class Rect{…};
      復(fù)制代碼


      如果模板實(shí)參是Rect類型,我們不希望使用類模板Graphics的通用成員函數(shù)定義,來實(shí)例化成員函數(shù)out(),我們希望專門定義Graphics<Rect>::out()實(shí)例,讓它使用Rect里面的成員函數(shù)。

      為此,我們可以通過一個(gè)顯示特化定義,為類模板實(shí)例的一個(gè)成員提供一個(gè)特化定義。

      格式:template<> 成員函數(shù)特化定義

      下面為類模板實(shí)例Graphics<Rect>的成員函數(shù)out()定義了顯式特化:

      Template<> void Graphics<Rect>::out(Rect figure){…}

      注意:

      只有當(dāng)通用類模板被聲明后,它的顯式特化才可以被定義。

      若定義了一個(gè)類模板特化,則必須定義與這個(gè)特化相關(guān)的所有成員函數(shù)或靜態(tài)數(shù)據(jù)成員,此時(shí)類模板特化的成員定義不能以符號(hào)template<>作為打頭。(template<>被省略)

      類模板不能夠在某些文件中根據(jù)通用模板定義被實(shí)例化,而在其他文件中卻針對(duì)同一組模板實(shí)參被特化。

      2.類模板部分特化

      如果模板有一個(gè)以上的模板參數(shù),則有些人就可能希望為一個(gè)特定的模板實(shí)參或者一組模板實(shí)參特化類模板,而不是為所有的模板參數(shù)特化該類模板。即,希望提供這樣一個(gè)模板:它仍然是一個(gè)通用的模板,只不過某些模板參數(shù)已經(jīng)被實(shí)際的類型或值取代。通過使用類模板部分特化,可以實(shí)現(xiàn)這一點(diǎn)。

      例:

      復(fù)制代碼
      1 template<int hi,int wid>
      2
      3 Class Graphics{…};
      4
      5 Template<int hi>//類模板的部分特化
      6
      7 Class Graphics<hi,90>{…};
      復(fù)制代碼


      格式:
      template<模板參數(shù)表>

      注意:

      部分特化的模板參數(shù)表只列出模板實(shí)參仍然未知的那些參數(shù)。

      類模板部分特化是被隱式實(shí)例化的。編譯器選擇“針對(duì)該實(shí)例而言最為特化的模板定義”進(jìn)行實(shí)例化,當(dāng)沒有特化可被使用時(shí),才使用通用模板定義。

      例:Graphics<24,90> figure;

      它即能從通用類模板定義被實(shí)例化,也能從部分特化的定義被實(shí)例化,但編譯器選擇的是部分特化來實(shí)例化模板。

      類模板部分特化必須有它自己對(duì)成員函數(shù)、靜態(tài)數(shù)據(jù)成員和嵌套類的定義。

       

      八、名字空間和類模板

      類模板定義也可以被放在名字空間中。例如:

      復(fù)制代碼
       1 Namespace cplusplus_primer{
      2
      3 Template<class type>
      4
      5 Class Graphics{…};
      6
      7 Template<class type>
      8
      9 Type create()
      10
      11 {…}
      12
      13 }
      復(fù)制代碼


      當(dāng)類模板名字Graphics被用在名字空間之外時(shí),它必須被名字空間名cplusplus_primer限定修,或者通過一個(gè)using聲明或指示符被引入。例如:

      復(fù)制代碼
      1 Void main()
      2
      3 {
      4
      5 using cplusplus_primer::Graphics;
      6
      7 Graphics<int> *pg=new Graphics<int>;
      8
      9 }
      復(fù)制代碼

      注意:在名字空間中聲明類模板也會(huì)影響該類模板及其成員的特化和部分特化聲明的方式,類模板或類模板成員的特化聲明必須被聲明在定義通用模板的名字空間中(可以在名字空間之外定義模板特化)。

      一個(gè)關(guān)于隊(duì)列的例子,下面將其代碼整理如下:

      復(fù)制代碼
        1 #include "iostream.h"
      2
      3 template <class Type> class QueueItem;
      4
      5 template <class Type>
      6
      7 class Queue {
      8
      9 public:
      10
      11 friend ostream& operator<<(ostream &os,const Queue<Type> &q);
      12
      13 Queue() : front( 0 ), back ( 0 ) { }
      14
      15 ~Queue(){}
      16
      17 void add( const Type & );
      18
      19 bool is_empty() const
      20
      21 {
      22
      23 return front == 0;
      24
      25 }
      26
      27 Type remove();
      28
      29 private:
      30
      31 QueueItem<Type> *front;
      32
      33 QueueItem<Type> *back;
      34
      35 };
      36
      37 template <class Type>
      38
      39 class QueueItem
      40
      41 {
      42
      43 public:
      44
      45 QueueItem(Type val){item=val;next=0;}
      46
      47 friend class Queue<Type>;
      48
      49 friend ostream& operator<<(ostream &os,const Queue<Type> &q);
      50
      51 friend ostream& operator<<(ostream &os,const QueueItem<Type> &qi);
      52
      53
      54
      55 private:
      56
      57 Type item;
      58
      59 QueueItem *next;
      60
      61 };
      62
      63 template <class Type>
      64
      65 void Queue<Type>::add(const Type &val)
      66
      67 {
      68
      69 QueueItem<Type> *pt =new QueueItem<Type>(val);
      70
      71 if ( is_empty() )
      72
      73 front = back = pt;
      74
      75 else
      76
      77 {
      78
      79 back->next = pt;
      80
      81 back = pt;
      82
      83 }
      84
      85 }
      86
      87 template <class Type>
      88
      89 Type Queue<Type>::remove()
      90
      91 {
      92
      93 if ( is_empty() )
      94
      95 {
      96
      97 cerr << "remove() on empty queue \n";
      98
      99 exit(-1);
      100
      101 }
      102
      103 QueueItem<Type> *pt = front;
      104
      105 front = front->next;
      106
      107 Type retval = pt->item;
      108
      109 delete pt;
      110
      111 return retval;
      112
      113 }
      114
      115 template <class Type>
      116
      117 ostream& operator<<(ostream &os, const Queue<Type> &q) //輸出隊(duì)列成員
      118
      119 {
      120
      121 os << "< ";
      122
      123 QueueItem<Type> *p;
      124
      125 for ( p = q.front; p; p = p->next )
      126
      127 os << *p << “ ;//用到了Queue和QueueItem的私有成員,因此需將此運(yùn)算符重
      128
      129 //載函數(shù)聲明為Queue和QueueItem的友元,書上沒有將此函數(shù)聲明為QueueItem
      130
      131 os << “ >”;//的友元。
      132
      133 return os;
      134
      135 }
      136
      137 template <class Type>
      138
      139 ostream& operator<< ( ostream &os, const QueueItem<Type> &qi )
      140
      141 {
      142
      143 os << qi.item;//用到了QueueItem的私有成員,因此需將此運(yùn)算符重載函數(shù)聲明
      144
      145 //為QueueItem的友元
      146
      147 return os;
      148
      149 }
      150
      151 void main()
      152
      153 {
      154
      155 Queue<int> qi;
      156
      157 cout << qi << endl;
      158
      159 int ival;
      160
      161 for ( ival = 0; ival < 10; ++ival )
      162
      163 qi.add( ival );
      164
      165 cout << qi << endl;
      166
      167 int err_cnt = 0;
      168
      169 for ( ival = 0; ival < 10; ++ival ) {
      170
      171 int qval = qi.remove();
      172
      173 if ( ival != qval ) err_cnt++;
      174
      175 }
      176
      177 cout << qi << endl;
      178
      179 if ( !err_cnt )
      180
      181 cout << "!! queue executed ok\n";
      182
      183 else cout << “?? queue errors: " << err_cnt << endl;
      184
      185 }
      復(fù)制代碼


      運(yùn)行結(jié)果

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多