C++函數(shù)模板與類模板實(shí)例解析
本文針對(duì)C++函數(shù)模板與類模板進(jìn)行了較為詳盡的實(shí)例解析,有助于幫助讀者加深對(duì)C++函數(shù)模板與類模板的理解。具體內(nèi)容如下:
泛型編程(Generic Programming)是一種編程范式,通過將類型參數(shù)化來實(shí)現(xiàn)在同一份代碼上操作多種數(shù)據(jù)類型,泛型是一般化并可重復(fù)使用的意思。泛型編程最初誕生于C++中,目的是為了實(shí)現(xiàn)C++的STL(標(biāo)準(zhǔn)模板庫)。
模板(template)是泛型編程的基礎(chǔ),一個(gè)模板就是一個(gè)創(chuàng)建類或函數(shù)的藍(lán)圖或公式。例如,當(dāng)使用一個(gè)vector這樣的泛型類型或者find這樣的泛型函數(shù)時(shí),我們提供足夠的信息,將藍(lán)圖轉(zhuǎn)換為特定的類或函數(shù)。
一、函數(shù)模板
一個(gè)通用的函數(shù)模板(function template)就是一個(gè)公式,可用來生成針對(duì)特定類型或特定值的函數(shù)版本。模板定義以關(guān)鍵字template開始,后面跟一個(gè)模板參數(shù)列表,列表中的多個(gè)模板參數(shù)(template parameter)以逗號(hào)分隔。模板參數(shù)表示在類或函數(shù)定義中用到的類型或值。
1、類型參數(shù)
一個(gè)模板類型參數(shù)(type parameter)表示的是一種類型。我們可以將類型參數(shù)看作類型說明符,就像內(nèi)置類型或類類型說明符一樣使用。類型參數(shù)前必須使用關(guān)鍵字class 或typename:
template <typename T> // typename和class一樣的 T function(T* p) { T tmp = *p; // 臨時(shí)變量類型為T //... return tmp; // 返回值類型為T }
關(guān)鍵字typename和class是一樣的作用,但顯然typename比class更為直觀,它更清楚地指出隨后的名字是一個(gè)類型名。
編譯器用模板類型實(shí)參為我們實(shí)例化(instantiate)特定版本的函數(shù),一個(gè)版本稱做模板的一個(gè)實(shí)例(instantiation)。當(dāng)我們調(diào)用一個(gè)函數(shù)模板時(shí),編譯器通常用函數(shù)實(shí)參來為我們推斷模板實(shí)參。當(dāng)然如果函數(shù)沒有模板類型的參數(shù),則我們需要特別指出來:
int a = 10; cout << function(&a) << endl; // 編譯器根據(jù)函數(shù)實(shí)參推斷模板實(shí)參 cout << function<int>(&a) << endl; // <int>指出模板參數(shù)為int
2、非類型參數(shù)
在模板中還可以定義非類型參數(shù)(nontype parameter),一個(gè)非類型參數(shù)表示一個(gè)值而非一個(gè)類型。我們通過一個(gè)特定的類型名而非關(guān)鍵字class或typename來指定非類型參數(shù):
// 整形模板 template<unsigned M, unsigned N> void add() { cout<< M+N << endl; } // 指針 template<const char* C> void func1(const char* str) { cout << C << " " << str << endl; } // 引用 template<char (&R)[9]> void func2(const char* str) { cout << R << " " << str << endl; } // 函數(shù)指針 template<void (*f)(const char*)> void func3(const char* c) { f(c); } void print(const char* c) { cout << c << endl;} char arr[9] = "template"; // 全局變量,具有靜態(tài)生存期 int main() { add<10, 20>(); func1<arr>("pointer"); func2<arr>("reference"); func3<print>("template function pointer"); return 0; }
當(dāng)實(shí)例化時(shí),非類型參數(shù)被一個(gè)用戶提供的或編譯器推斷出的值所替代。一個(gè)非類型參數(shù)可以是一個(gè)整型,或者是一個(gè)指向?qū)ο蠡蚝瘮?shù)的指針或引用:綁定到整形(非類型參數(shù))的實(shí)參必須是一個(gè)常量表達(dá)式,綁定到指針或引用(非類型參數(shù))的實(shí)參必須具有靜態(tài)的生存期(比如全局變量),不能把普通局部變量 或動(dòng)態(tài)對(duì)象綁定到指針或引用的非類型形參。
二、類模板
相應(yīng)的,類模板(class template)是用來生成類的藍(lán)圖。與函數(shù)模板的不同之處是,編譯器不能為類模板推斷模板參數(shù)類型,所以我們必須顯式的提供模板實(shí)參。與函數(shù)模板一樣,類模板參數(shù)可以是類型參數(shù),也可以是非類型參數(shù),這里就不再贅述了。
template<typename T> class Array { public: Array(T arr[], int s); void print(); private: T *ptr; int size; }; // 類模板外部定義成員函數(shù) template<typename T> Array<T>::Array(T arr[], int s) { ptr = new T[s]; size = s; for(int i=0; i<size; ++i) ptr[i]=arr[i]; } template<typename T> void Array<T>::print() { for(int i=0; i<size; ++i) cout << " " << *(ptr+i); cout << endl; } int main() { char a[5] = {'J','a','m','e','s'}; Array<char> charArr(a, 5); charArr.print(); int b[5] = { 1, 2, 3, 4, 5}; Array<int> intArr(b, 5); intArr.print(); return 0; }
類模板的成員函數(shù)
與其他類一樣,我們既可以在類模板內(nèi)部,也可以在類模板外部定義其成員函數(shù)。定義在類模板之外的成員函數(shù)必須以關(guān)鍵字template開始,后接類模板參數(shù)列表。
template <typename T> return_type class_name<T>::member_name(parm-list) { }
默認(rèn)情況下,對(duì)于一個(gè)實(shí)例化了的類模板,其成員函數(shù)只有在使用時(shí)才被實(shí)例化。如果一個(gè)成員函數(shù)沒有被使用,則它不會(huì)被實(shí)例化。
類模板和友元
當(dāng)一個(gè)類包含一個(gè)友元聲明時(shí),類與友元各自是否是模板是相互無關(guān)的。如果一個(gè)類模板包含一個(gè)非模板的友元,則友元被授權(quán)可以訪問所有模板的實(shí)例。如果友元自身是模板,類可以授權(quán)給所有友元模板的實(shí)例,也可以只授權(quán)給特定實(shí)例。
// 前置聲明,在將模板的一個(gè)特定實(shí)例聲明為友元時(shí)要用到 template<typename T> class Pal; // 普通類 class C { friend class Pal<C>; // 用類C實(shí)例化的Pal是C的一個(gè)友元 template<typename T> friend class Pal2; //Pal2所有實(shí)例都是C的友元;無須前置聲明 }; // 模板類 template<typename T> class C2 { // C2的每個(gè)實(shí)例將用相同類型實(shí)例化的Pal聲明為友元,一對(duì)一關(guān)系 friend class Pal<T>; // Pal2的所有實(shí)例都是C2的每個(gè)實(shí)例的友元,不需要前置聲明 template<typename X> friend class Pal2; // Pal3是普通非模板類,它是C2所有實(shí)例的友元 friend class Pal3; };
類模板的static成員
類模板可以聲明static成員。類模板的每一個(gè)實(shí)例都有其自己獨(dú)有的static成員對(duì)象,對(duì)于給定的類型X,所有class_name<X>類型的對(duì)象共享相同的一份static成員實(shí)例。
template<typename T> class Foo { public: void print(); //...其他操作 private: static int i; }; template<typename T> void Foo<T>::print() { cout << ++i << endl; } template<typename T> int Foo<T>::i = 10; // 初始化為10 int main() { Foo<int> f1; Foo<int> f2; Foo<float> f3; f1.print(); // 輸出11 f2.print(); // 輸出12 f3.print(); // 輸出11 return 0; }
我們可以通過類類型對(duì)象來訪問一個(gè)類模板的static對(duì)象,也可以使用作用域運(yùn)算符(::)直接訪問靜態(tài)成員。類似模板類的其他成員函數(shù),一個(gè)static成員函數(shù)也只有在使用時(shí)才會(huì)實(shí)例化。
欄 目:C語言
下一篇:C++中extern "C"的用法
本文標(biāo)題:C++函數(shù)模板與類模板實(shí)例解析
本文地址:http://mengdiqiu.com.cn/a1/Cyuyan/3483.html
您可能感興趣的文章
- 04-02c語言函數(shù)調(diào)用后清空內(nèi)存 c語言調(diào)用函數(shù)刪除字符
- 04-02c語言的正則匹配函數(shù) c語言正則表達(dá)式函數(shù)庫
- 04-02func函數(shù)+在C語言 func函數(shù)在c語言中
- 04-02c語言中對(duì)數(shù)函數(shù)的表達(dá)式 c語言中對(duì)數(shù)怎么表達(dá)
- 04-02c語言用函數(shù)寫分段 用c語言表示分段函數(shù)
- 04-02c語言編寫函數(shù)冒泡排序 c語言冒泡排序法函數(shù)
- 04-02c語言沒有round函數(shù) round c語言
- 04-02c語言分段函數(shù)怎么求 用c語言求分段函數(shù)
- 04-02C語言中怎么打出三角函數(shù) c語言中怎么打出三角函數(shù)的值
- 04-02c語言調(diào)用函數(shù)求fibo C語言調(diào)用函數(shù)求階乘


閱讀排行
- 1C語言 while語句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹的示例代碼(圣誕
- 3利用C語言實(shí)現(xiàn)“百馬百擔(dān)”問題方法
- 4C語言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 04-02c語言函數(shù)調(diào)用后清空內(nèi)存 c語言調(diào)用
- 04-02func函數(shù)+在C語言 func函數(shù)在c語言中
- 04-02c語言的正則匹配函數(shù) c語言正則表達(dá)
- 04-02c語言用函數(shù)寫分段 用c語言表示分段
- 04-02c語言中對(duì)數(shù)函數(shù)的表達(dá)式 c語言中對(duì)
- 04-02c語言編寫函數(shù)冒泡排序 c語言冒泡排
- 04-02c語言沒有round函數(shù) round c語言
- 04-02c語言分段函數(shù)怎么求 用c語言求分段
- 04-02C語言中怎么打出三角函數(shù) c語言中怎
- 04-02c語言調(diào)用函數(shù)求fibo C語言調(diào)用函數(shù)求
隨機(jī)閱讀
- 01-10delphi制作wav文件的方法
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 04-02jquery與jsp,用jquery
- 01-10C#中split用法實(shí)例總結(jié)
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-11ajax實(shí)現(xiàn)頁面的局部加載
- 01-10使用C語言求解撲克牌的順子及n個(gè)骰子
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?