C++函數(shù)模板與類模板實例解析
本文針對C++函數(shù)模板與類模板進行了較為詳盡的實例解析,有助于幫助讀者加深對C++函數(shù)模板與類模板的理解。具體內(nèi)容如下:
泛型編程(Generic Programming)是一種編程范式,通過將類型參數(shù)化來實現(xiàn)在同一份代碼上操作多種數(shù)據(jù)類型,泛型是一般化并可重復(fù)使用的意思。泛型編程最初誕生于C++中,目的是為了實現(xiàn)C++的STL(標準模板庫)。
模板(template)是泛型編程的基礎(chǔ),一個模板就是一個創(chuàng)建類或函數(shù)的藍圖或公式。例如,當使用一個vector這樣的泛型類型或者find這樣的泛型函數(shù)時,我們提供足夠的信息,將藍圖轉(zhuǎn)換為特定的類或函數(shù)。
一、函數(shù)模板
一個通用的函數(shù)模板(function template)就是一個公式,可用來生成針對特定類型或特定值的函數(shù)版本。模板定義以關(guān)鍵字template開始,后面跟一個模板參數(shù)列表,列表中的多個模板參數(shù)(template parameter)以逗號分隔。模板參數(shù)表示在類或函數(shù)定義中用到的類型或值。
1、類型參數(shù)
一個模板類型參數(shù)(type parameter)表示的是一種類型。我們可以將類型參數(shù)看作類型說明符,就像內(nèi)置類型或類類型說明符一樣使用。類型參數(shù)前必須使用關(guān)鍵字class 或typename:
template <typename T> // typename和class一樣的
T function(T* p)
{
T tmp = *p; // 臨時變量類型為T
//...
return tmp; // 返回值類型為T
}
關(guān)鍵字typename和class是一樣的作用,但顯然typename比class更為直觀,它更清楚地指出隨后的名字是一個類型名。
編譯器用模板類型實參為我們實例化(instantiate)特定版本的函數(shù),一個版本稱做模板的一個實例(instantiation)。當我們調(diào)用一個函數(shù)模板時,編譯器通常用函數(shù)實參來為我們推斷模板實參。當然如果函數(shù)沒有模板類型的參數(shù),則我們需要特別指出來:
int a = 10; cout << function(&a) << endl; // 編譯器根據(jù)函數(shù)實參推斷模板實參 cout << function<int>(&a) << endl; // <int>指出模板參數(shù)為int
2、非類型參數(shù)
在模板中還可以定義非類型參數(shù)(nontype parameter),一個非類型參數(shù)表示一個值而非一個類型。我們通過一個特定的類型名而非關(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;
}
當實例化時,非類型參數(shù)被一個用戶提供的或編譯器推斷出的值所替代。一個非類型參數(shù)可以是一個整型,或者是一個指向?qū)ο蠡蚝瘮?shù)的指針或引用:綁定到整形(非類型參數(shù))的實參必須是一個常量表達式,綁定到指針或引用(非類型參數(shù))的實參必須具有靜態(tài)的生存期(比如全局變量),不能把普通局部變量 或動態(tài)對象綁定到指針或引用的非類型形參。
二、類模板
相應(yīng)的,類模板(class template)是用來生成類的藍圖。與函數(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) { }
默認情況下,對于一個實例化了的類模板,其成員函數(shù)只有在使用時才被實例化。如果一個成員函數(shù)沒有被使用,則它不會被實例化。
類模板和友元
當一個類包含一個友元聲明時,類與友元各自是否是模板是相互無關(guān)的。如果一個類模板包含一個非模板的友元,則友元被授權(quán)可以訪問所有模板的實例。如果友元自身是模板,類可以授權(quán)給所有友元模板的實例,也可以只授權(quán)給特定實例。
// 前置聲明,在將模板的一個特定實例聲明為友元時要用到
template<typename T> class Pal;
// 普通類
class C {
friend class Pal<C>; // 用類C實例化的Pal是C的一個友元
template<typename T> friend class Pal2; //Pal2所有實例都是C的友元;無須前置聲明
};
// 模板類
template<typename T> class C2 {
// C2的每個實例將用相同類型實例化的Pal聲明為友元,一對一關(guān)系
friend class Pal<T>;
// Pal2的所有實例都是C2的每個實例的友元,不需要前置聲明
template<typename X> friend class Pal2;
// Pal3是普通非模板類,它是C2所有實例的友元
friend class Pal3;
};
類模板的static成員
類模板可以聲明static成員。類模板的每一個實例都有其自己獨有的static成員對象,對于給定的類型X,所有class_name<X>類型的對象共享相同的一份static成員實例。
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;
}
我們可以通過類類型對象來訪問一個類模板的static對象,也可以使用作用域運算符(::)直接訪問靜態(tài)成員。類似模板類的其他成員函數(shù),一個static成員函數(shù)也只有在使用時才會實例化。
相關(guān)文章
C++實現(xiàn)Window環(huán)境聊天室功能
這篇文章主要為大家詳細介紹了C++實現(xiàn)Window環(huán)境聊天室功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-06-06
c++中的內(nèi)聯(lián)函數(shù)inline用法實例
在本篇文章里小編給大家整理的是關(guān)于c++中的內(nèi)聯(lián)函數(shù)inline用法實例以及相關(guān)知識點,有需要的朋友們學習下。2019-09-09

