/************************************************************************************************************************檔案說明: C++的模板技術開發環境: Win10+VS2013+STL時間地點: 陝西師範大學 文津樓 2017.7.26作 者: 九 月*************************************************************************************************************************/
(一)C++模板技術的簡介
1)C++模板是一種十分重要的技術,STL標準模板庫的一般演算法和容器就是通過模板編程實現的,並以函數模板和類模板提供出來。
2)顧名思義,模板的作用就在於定製函數和類。只要將資料類型傳遞給函數模板和類模板,就可以產生特定資料類型下的函數和類,實現了資料類型不同、但是程式邏輯完全相同的代碼重用,減輕了編程的工作量,並可使大量常用的功能代碼完整而簡潔的納入到標準庫中,極大的改善了C++的變成環境。
3)模板純粹是為了將預先處理宏推廣到C++而來,不同於宏使用一套"指令開頭用#,指令結尾不適用分號,標識符定義不適用類型"的備受爭議的文法。
4)模板的定義可以跟函數和類的定義融合在一起,完全是在它們的基礎上添加一些新的文法,因此又稱為函數模板和類模板,表明模板的文法仿照了熟悉的函數和類的文法,只是資料類型需要用關鍵字templates聲明為泛型。 (二)函數模板 (1)函數模板的概念
假設要編寫一個函數對兩個參數求和。實際編程中,我們可能希望定義幾個這樣的函數,每一個可以對一種給定類型的值求和,那麼可能自然會想到函數的重載。例如:
int add(int a, int b){return a + b;}double add(double a, double b){return a + b;}char add(char a, char b){return a + b;} 這些函數幾乎相同,每個函數的函數體是相同的,功能也是相同的,它們之間唯一的不同在於形參的類型和函數傳回值的類型。
事實上,在具體編寫上述代碼時,我們必須手工的書寫所有的代碼,所以會使用複製、粘貼、修改的編輯功能得到另一種類型的求和函數。如果每種類型都需要重複函數的函數體,不僅麻煩,而且容易出錯。更重要的是,需要事Crowdsourced Security Testing道可能會支援的所有類型的組合情況。如果希望將函數用於未知類型,這種方法就是有問題的。
C++有模板(template)機制,可以使用函數模板解決上述存在的問題。函數模板(function template)是一個獨立於類型的函數,可作為一種模式,產生函數的特定類型版本。
使用函數模板可以設計通用型的函數,這些函數與類型無關,並且只在需要時自動執行個體化,從而形成"批量型"的編程方式。 (2)函數模板的定義和使用 (1)函數模板的定義
函數模板定義的文法形式為:
template<模板形參表>傳回值類型 函數名(形式參數列表){函數體} 可以約定,第1行稱為模板定義,其後稱為模板函數,與函數定義文法類似。
模板定義以關鍵字template開始,後接模板形參表。模板形參表(template parameter list)是用一對角括弧<>括起來的一個或多個模板形參的列表,不允許為空白,形參之間以逗號分隔,其形式有兩種:
第一種形式如下所示: typename 型別參數名1,typename 型別參數名2............第二種形式如下所示: class 型別參數名1,class 型別參數名2...................
在函數模板形參表中,typename和class具有相同含義,可以互換使用,或者兩個關鍵字都可以在同一模板形參表中使用。
不過由於C++中class關鍵字往往容易與類聯絡在一起,所以使用關鍵字typename比使用class更直觀,typename可以更加直觀的反映出後面的名字是一個類型名。
模板定義的後面是函數定義,在函數定義中,可以使用模板形參表中的型別參數。例如:
template<typename T> add(T a, T b){ return a + b;} 函數模板定義文法的含義是一個通用型函數,這個函數類型和形參類型沒有具體的指定,而是一個類型記號表示,類型記號由編譯器根據所用的函數而確定,這種通用型函數成為函數模板。
使用函數模板時,編譯器會推斷那個(或那些)模板實參綁定到模板形參上,一旦編譯器確定了實際的模板實參,將執行個體化函數模板。即編譯器將確定用什麼類型代替每個類型形參,以及用什麼值代替每個非類型形參,推匯出實際的模板實參後,編譯器使用類型實參代替相應的模板形參產生並編譯該版本的函數。這裡,編譯器承擔了我們使用的每種類型編寫的重複工作,我們不用在機械的複製、黏貼、修改等手工書寫了。
(2)函數模板的使用
可以像普通函數那樣使用模板函數調用。
#include<iostream>using namespace std;template<typename T>T add(T a, T b){return a + b;}int main(){std::cout << "int_add = " << add(10,20)<< std::endl;std::cout << "double_add = " << add(10.2, 20.5) << std::endl;std::cout << "char_add = " << add(10, 20) << std::endl;std::system("pause");return 0;}
(三)類模板
(1)類模板的簡介
類似於函數模板的做法,類模板對資料成員的資料類型和成員函數的參數類型進行泛化。如下是類模板的一個基本定義形式,關鍵字template說明類型T1~Tn是模本類型,成員函數可在類模板的聲明中定義。
template<class T1,class T2,.....,class Tn> class 類名{//成員聲明或定義;};template<class T1, class T2, ....., class Tn> 傳回值 類名<T1,T2, ....., Tn>::成員函數1{//函數定義}template<class T1, class T2, ....., class Tn> 傳回值 類名<T1, T2, ....., Tn>::成員函數2{//函數定義}
注意:
不同於非模板代碼的組織方式,函數模板和類模板的聲明和定義代碼,一般都編寫在.h標頭檔中,以免由於為具現而提示編譯連結錯誤。
下面給出一個類模板表示平面上點的樣本:
template<class T> //【0】類模板定義class Point //【1】Point不是類名是模板名{public:Point::x(0), y(0) {} //【2】預設建構函式Point(const T a, const T b) :(x)(a), y(b) {} //【3】帶參數的建構函式void Set(const T a, const T b);void Display();private:T x;T y;};