STL與泛型編程(三)
閱讀C++ STKL源碼的基礎(chǔ)條件
1 操作符重載
operator是C++的關(guān)鍵字,它和運(yùn)算符一起使用,表示一個運(yùn)算符函數(shù),理解時應(yīng)將operator=整體上視為一個函數(shù)名。
這是C++擴(kuò)展運(yùn)算符功能的方法,雖然樣子古怪,但也可以理解:一方面要使運(yùn)算符的使用方法與其原來一致,另一方面擴(kuò)展其功能只能通過函數(shù)的方式(c++中,“功能”都是由函數(shù)實(shí)現(xiàn)的)。
1.1 為什么使用操作符重載?
對于系統(tǒng)的所有操作符,一般情況下,只支持基本數(shù)據(jù)類型和標(biāo)準(zhǔn)庫中提供的class,對于用戶自己定義的class,如果想支持基本操作,比如比較大小,判斷是否相等,等等,則需要用戶自己來定義關(guān)于這個操作符的具體實(shí)現(xiàn)。比如,判斷兩個人是否一樣大,我們默認(rèn)的規(guī)則是按照其年齡來比較,所以,在設(shè)計person 這個class的時候,我們需要考慮操作符==,而且,根據(jù)剛才的分析,比較的依據(jù)應(yīng)該是age。那么為什么叫重載呢?這是因為,在編譯器實(shí)現(xiàn)的時候,已經(jīng)為我們提供了這個操作符的基本數(shù)據(jù)類型實(shí)現(xiàn)版本,但是現(xiàn)在他的操作數(shù)變成了用戶定義的數(shù)據(jù)類型class,所以,需要用戶自己來提供該參數(shù)版本的實(shí)現(xiàn)。
2 模板
2.1函數(shù)模板的聲明和模板函數(shù)的生成
2.1.1 函數(shù)模板的聲明
函數(shù)模板可以用來創(chuàng)建一個通用的函數(shù),以支持多種不同的形參,避免重載函數(shù)的函數(shù)體重復(fù)設(shè)計。它的最大特點(diǎn)是把函數(shù)使用的數(shù)據(jù)類型作為參數(shù)。
函數(shù)模板的聲明形式為:
template<typename 數(shù)據(jù)類型參數(shù)標(biāo)識符>
<返回類型><函數(shù)名>(參數(shù)表)
{
函數(shù)體
}
其中,template是定義模板函數(shù)的關(guān)鍵字;template后面的尖括號不能省略;typename(或class)是聲明數(shù)據(jù)類型參數(shù)標(biāo)識符的關(guān)鍵字,用以說明它后面的標(biāo)識符是數(shù)據(jù)類型標(biāo)識符。這樣,在以后定義的這個函數(shù)中,凡希望根據(jù)實(shí)參數(shù)據(jù)類型來確定數(shù)據(jù)類型的變量,都可以用數(shù)據(jù)類型參數(shù)標(biāo)識符來說明,從而使這個變量可以適應(yīng)不同的數(shù)據(jù)類型。例如:
template<typename T>
T fuc(T x, int y)
{
T x;
//……
}
如果主調(diào)函數(shù)中有以下語句:
double d;
int a;
fuc(d,a);
則系統(tǒng)將用實(shí)參d的數(shù)據(jù)類型double去代替函數(shù)模板中的T生成函數(shù):
double fuc(double x,int y)
{
double x;
//……
}
函數(shù)模板只是聲明了一個函數(shù)的描述即模板,不是一個可以直接執(zhí)行的函數(shù),只有根據(jù)實(shí)際情況用實(shí)參的數(shù)據(jù)類型代替類型參數(shù)標(biāo)識符之后,才能產(chǎn)生真正的函數(shù)。
關(guān)鍵字typename也可以使用關(guān)鍵字class,這時數(shù)據(jù)類型參數(shù)標(biāo)識符就可以使用所有的C++數(shù)據(jù)類型。
2.1.2 模板函數(shù)的生成
函數(shù)模板的數(shù)據(jù)類型參數(shù)標(biāo)識符實(shí)際上是一個類型形參,在使用函數(shù)模板時,要將這個形參實(shí)例化為確定的數(shù)據(jù)類型。將類型形參實(shí)例化的參數(shù)稱為模板實(shí)參,用模板實(shí)參實(shí)例化的函數(shù)稱為模板函數(shù)。模板函數(shù)的生成就是將函數(shù)模板的類型形參實(shí)例化的過程。例如:
使用中應(yīng)注意的幾個問題:
⑴ 函數(shù)模板允許使用多個類型參數(shù),但在template定義部分的每個形參前必須有關(guān)鍵字typename或class,即:
template<class 數(shù)據(jù)類型參數(shù)標(biāo)識符1,…,class 數(shù)據(jù)類型參數(shù)標(biāo)識符n>
<返回類型><函數(shù)名>(參數(shù)表)
{
函數(shù)體
}
⑵ 在template語句與函數(shù)模板定義語句<返回類型>之間不允許有別的語句。如下面的聲明是錯誤的:
template<class T>
int I;
T min(T x,T y)
{
函數(shù)體
}
⑶ 模板函數(shù)類似于重載函數(shù),但兩者有很大區(qū)別:函數(shù)重載時,每個函數(shù)體內(nèi)可以執(zhí)行不同的動作,但同一個函數(shù)模板實(shí)例化后的模板函數(shù)都必須執(zhí)行相同的動作。
2.2 類模板
如同函數(shù)模板一樣,使用類模板使用戶可以為類定義一種模式,使得類中的某些數(shù)據(jù)成員、某些成員函數(shù)的參數(shù)、某些成員函數(shù)的返回值能取任意類型。類模板是對一批僅僅成員數(shù)據(jù)類型不同的類的抽象,程序員只要為這一批類所組成的整個類家族創(chuàng)建一個類模板,給出一套程序代碼,就可以用來生成多種具體的類,(這類可以看作是類模板的實(shí)例),從而大大提高編程的效率。
定義類模板的一般形式是:
template <類型名 參數(shù)名1,類型名參數(shù)名2,…>
class 類名
{
類聲明體
};
例如,template <class T>
class Smemory
{…
public:
void mput(T x);
…
}
表示定義一個名為Smemory的類模板,其中帶類型參數(shù)T。
在類模板的外部定義類成員函數(shù)的一般形式是:
template <類型名 參數(shù)名1,類型名參數(shù)名2,…>
函數(shù)返回值類型 類名<參數(shù)名 1 參數(shù)名 2,…>::成員函數(shù)名(形參表)
{
函數(shù)體
}
例如:template <class T>
void Smemory<T>::mput(T x)
{…}
表示定義一個類模板Smemory的成員函數(shù),函數(shù)名為mput,形參x的類型是T,函數(shù)無返回值。
類模板是一個類家族的抽象,它只是對類的描述,編譯程序不為類模板(包括成員函數(shù)定義)創(chuàng)建程序代碼,但是通過對類模板的實(shí)例化可以生成一個具體的類以及該具體類的對象。
與函數(shù)模板不同的是:函數(shù)模板的實(shí)例化是由編譯程序在處理函數(shù)調(diào)用時自動完成的,而類模板的實(shí)例化必須由程序員在程序中顯式地指定,
其實(shí)例化的一般形式是:
類名 <數(shù)據(jù)類型 1(或數(shù)據(jù)),數(shù)據(jù)類型 2(或數(shù)據(jù))…> 對象名
例如,Smemory<int> mol;
表示將類模板Smemory的類型參數(shù)T全部替換成int 型,從而創(chuàng)建一個具體的類,并生成該具體類的一個對象mol。
3 特化
模版的完全特化與偏特化
模版特化:任何針對模版參數(shù)進(jìn)一步進(jìn)行條件限制設(shè)計的特化版本。 <<泛型思維>>
完全特化:針對所有的模版參數(shù)進(jìn)行特化。 <<c++ primer>>
舉例如下:
template<class T,class N>
class Template{};
全特化:
template<>
class Template<int,char>{};
偏特化:
template<class T>
class Template<T,int>{};
注意:函數(shù)模版不存在偏特化,只有類模版才能偏特化
#include <iostream>
using namespace std;
template<typename T, typename N>
class Test
{
public:
Test( T i, N j ) : a(i), b(j)
{
cout<<"普通模板類"<< a <<' ' << b << endl;
}
private:
T a;
N b;
};
template<>
class Test<int , char>
{
public:
Test( int i, char j ) : a( i ), b( j )
{
cout<<"模版類全特化"<< a << ' ' << b << endl;
}
private:
int a;
char b;
};
template <typename N>
class Test<char, N>
{
public:
Test( char i, N j ):a( i ), b( j )
{
cout<<"模版類偏特化"<< a<< ' ' << b << endl;
}
private:
char a;
N b;
};
//模板函數(shù)
template<typename T1, typename T2>
void fun(T1 a , T2 b)
{
cout<<"模板函數(shù)"<<endl;
}
//模版函數(shù)全特化
template<>
void fun<int ,char >(int a, char b)
{
cout<<"模版函數(shù)全特化"<<endl;
}
//函數(shù)不存在偏特化:下面的代碼是錯誤的
// template<typename T2>
// void fun<char,T2>(char a, T2 b)
// {
// cout<<"模版函數(shù)偏特化"<<endl;
// }