日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

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

 lchjczw 2013-05-14

一、類模板定義及實例化

. 定義一個類模板:

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

 

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

例:

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

注意:

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

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

(3)同一個模板參數(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;//錯誤:成員名不能與模板參數(shù)type同名
12
13 };
14
15 template<class type,class type>//錯誤:重復(fù)使用名為type的參數(shù)
16
17 class Rect;
18
19 template<class type> //參數(shù)名”type”在不同模板間可以重復(fù)使用
20
21 class Round;
復(fù)制代碼


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

復(fù)制代碼
 1 // 所有三個 Image 聲明都引用同一個類模板的聲明
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ù)提供缺省實參的順序是先右后左。

View Code


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

View Code


2.
類模板實例化

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

例:Graphics<int> gi;

類模板什么時候會被實例化呢?

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

對象類型是一個類模板實例,當(dāng)對象被定義時。此點被稱作類的實例化點。

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

例:

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


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

要點

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

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

可以被用于非類型模板參數(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;//錯誤:從const int*->int*是錯誤的。
8
9 Graphics<0> bp2;//錯誤不能通過隱式轉(zhuǎn)換把0轉(zhuǎn)換成指針值
10
11 const double db=3.1415;
12
13 Rect<double,db> fa1;//錯誤:不能將const double轉(zhuǎn)換成int.
14
15 unsigned int fasize=255;
16
17 Rect<String, fasize> fa2;//錯誤:非類型參數(shù)的實參必須是常量表達(dá)式,將unsigned改為const就正確。
18
19 Int arr[10];
20
21 Graphics<arr> gp;//正確
復(fù)制代碼

 

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

要點:

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

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

復(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所有實例的友元
12
13 };
復(fù)制代碼

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

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

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

如圖:

第三種聲明表示類模板的實例和它的友元之間是一種一對多的映射關(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ù)聲明為類模板友元時,它們不必在全局域中被聲明或定義,但將一個類的成員聲明為類模板友元,該類必須已經(jīng)被定義,另外在聲明綁定的友元類模板或函數(shù)模板時,該模板也必須先聲明。

例:

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

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

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

要點:

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

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

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

例:

復(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.類模板的嵌套類型

要點

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

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

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

例:

復(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 //引用公有嵌套類型必須加上類模板實例名字
復(fù)制代碼


五、成員模板

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

要點:

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

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

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

例:

復(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){}//成員模板被定義在類模板定義之外(要根上完整模板實參)
12
13 Graphics<int>的實例可能包括下列嵌套類型:
14
15 Graphics<int>::Rect<double>
16
17 Graphics<int>::Rect<string>
復(fù)制代碼


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

 

六、類模板的編譯模式

1.包含編譯模式

這種編譯模式下,類模板的成員函數(shù)和靜態(tài)成員的定義必須被包含在“要將它們實例化”的所有文件中,如果一個成員函數(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 &)的實例(下有注解)
28
29 Pg->Setup(ival);
30
31 }
復(fù)制代碼


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

.顯式實例聲明

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

例:

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


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

 

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

1.類模板的特化

先看下面的例子:

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


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

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

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

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

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

注意:

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

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

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

2.類模板部分特化

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

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

例:Graphics<24,90> figure;

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

類模板部分特化必須有它自己對成員函數(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被用在名字空間之外時,它必須被名字空間名cplusplus_primer限定修,或者通過一個using聲明或指示符被引入。例如:

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

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

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

復(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) //輸出隊列成員
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的私有成員,因此需將此運算符重
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的私有成員,因此需將此運算符重載函數(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ù)制代碼


運行結(jié)果

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

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多