小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

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

 lchjczw 2013-05-14

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

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

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

 

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

例:

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

注意:

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

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

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

(4)在不同的類(lèi)模板或聲明中,模板參數(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類(lèi)型
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)
在類(lèi)模板的前向聲明和定義中,模板參數(shù)的名字可以不同。

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

View Code


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

View Code


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

定義:從通用的類(lèi)模板定義中生成類(lèi)的過(guò)程稱(chēng)為模板實(shí)例化。

例:Graphics<int> gi;

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

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

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

一個(gè)指針或引用指向一個(gè)類(lèi)模板實(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è)類(lèi)模板引用,不需實(shí)例化
12
13   Graphics<int> si;// si是一個(gè)Graphics類(lèi)型的對(duì)象,需要實(shí)例化類(lèi)模板
14
15 }
16
17 int main(){
18
19   Graphcis<char>* sc;// 僅聲明一個(gè)類(lèi)模板指針,不需實(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ù)類(lèi)模板定義產(chǎn)生該類(lèi)型。
24
25 }
復(fù)制代碼


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

要點(diǎn)

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

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

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

例:

復(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ò)誤不能通過(guò)隱式轉(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ò)誤:非類(lèi)型參數(shù)的實(shí)參必須是常量表達(dá)式,將unsigned改為const就正確。
18
19 Int arr[10];
20
21 Graphics<arr> gp;//正確
復(fù)制代碼

 

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

要點(diǎn):

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

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

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

三、類(lèi)模板的友元聲明

類(lèi)模板中可以有三種友元聲明:

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

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

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

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

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

如圖:

第三種聲明表示類(lèi)模板的實(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)把非模板類(lèi)或函數(shù)聲明為類(lèi)模板友元時(shí),它們不必在全局域中被聲明或定義,但將一個(gè)類(lèi)的成員聲明為類(lèi)模板友元,該類(lèi)必須已經(jīng)被定義,另外在聲明綁定的友元類(lèi)模板或函數(shù)模板時(shí),該模板也必須先聲明。

例:

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

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

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

要點(diǎn):

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

類(lèi)模板靜態(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è)類(lèi)模板實(shí)例相對(duì)應(yīng),靜態(tài)成員的實(shí)例引用要通過(guò)一個(gè)類(lèi)模板實(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)成員定義分為兩部分:前一部分是類(lèi)型,比如Graphics<type>*,后一部分是名稱(chēng)和值,比如Graphics<type>::next=0;
復(fù)制代碼

2.類(lèi)模板的嵌套類(lèi)型

要點(diǎn)

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

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

公有嵌套類(lèi)型可以被用在類(lèi)定義之外,這時(shí)它的名字前必須加上類(lèi)模板實(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 //引用公有嵌套類(lèi)型必須加上類(lèi)模板實(shí)例名字
復(fù)制代碼


五、成員模板

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

要點(diǎn):

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

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

成員模板可以定義在其外圍類(lèi)或類(lèi)模板定義之外.

例:

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


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

 

六、類(lèi)模板的編譯模式

1.包含編譯模式

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

2.分離編譯模式

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

.顯式實(shí)例聲明

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

例:

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


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

 

七、類(lèi)模板的特化及部分特化

1.類(lèi)模板的特化

先看下面的例子:

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


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

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

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

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

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

注意:

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

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

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

2.類(lèi)模板部分特化

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

例:

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


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

注意:

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

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

例:Graphics<24,90> figure;

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

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

 

八、名字空間和類(lèi)模板

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

復(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)類(lèi)模板名字Graphics被用在名字空間之外時(shí),它必須被名字空間名cplusplus_primer限定修,或者通過(guò)一個(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ù)制代碼

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

一個(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ū)上沒(méi)有將此函數(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)容均由用戶(hù)發(fā)布,不代表本站觀(guān)點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(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)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多