复习笔记(八)——C++模板
模板的概念
在C++標準庫中,幾乎所有的代碼都是模板代碼。
模板是一種參數化的多態工具。
所謂參數化的多態性,是指將程序所處理 的對象的類型參數化,使一段程序代碼可以用于處理多不同類型的對象。
采用模板編程,可以為各種邏輯功能相同而數據類型不同的程序提供一種代碼共享的機制。
繼承和組合提供了重用對象代碼的方法,而模板提供了重用源代碼的方法。
函數模板
所謂函數模板,實際上是建立一個通用函數,它所用到的數據的類型(包括返回值類型、形參類型、局部變量類型)可以不具體指定,而是用一個虛擬的類型來代替(實際上是用一個標識符來占位),等發生函數調用時再根據傳入的實參來逆推出真正的類型。這個通用函數就稱為函數模板(Function Template)。
函數模板不是實際的函數,而是編譯器用于生成一個或多個函數的 “模具”。在編寫函數模板時,不必為形參、返回值或局部變量指定實際類型,而是使用類型形參來指定通用數據類型。當編譯器遇到對函數的調用時,它將檢查其實參的數據類型,并生成將與這些數據類型配合使用的函數代碼。
一但定義了函數模板,就可以將類型參數用于函數定義和函數聲明了。說得直白一點,原來使用 int、float、char 等內置類型的地方,都可以用類型參數來代替。
函數模板的定義
函數模板的一般說明形式如下:
template < 模板形參表> 返回值類型 函數名(模板函數形參表){//函數定義體 }函數模板的定義以關鍵字template開頭
template之后<>中是函數模板的參數列表
函數模板的參數是類型參數,其類型為class或typename
template<class T> template<class T1, class T2>模板的參數定義之后是函數模板的定義,是一個將類型參數作為某種類型使用的函數。
函數模板的參數名在模板中作為一種類型使用,可以用于函數的形參、函數返回值和函數的局部變量。
模板的每個形式參數要在函數的參數列表中至少出現一次。
形式參數名的作用域局限于函數模板的范圍內。
函數模板的使用
函數模板規定了對數據的處理流程。
某些數據類型(模板的參數)要等到模板實例化時再確定具體的類型。
函數模板的實例化由編譯器來完成
根據函數調用的實參類型確定模板形參的具體類型
用相應的類型替換函數模板中的模板參數完成函數模板的實例化
函數模板的示例
#include <iostream> using namespace std;#define SIZE 8 template<class ElementType> void sortArray (ElementType b[], int len) {for(int pass=0;pass<len-1;pass++)for(int i = pass+1; i < len;i++)if ( b[ pass ] > b[ i ] ){ElementType hold;hold = b[ pass ];b[ pass ] = b[ i ];b[ i ] = hold;} }template<class ElementType > void displayArray(ElementType b[],int len) {for(int index=0;index<=len-1;index++)if ( index != len -1 )cout<<b[index]<<"\t";elsecout<<b[index]<<endl; } int main() {int ai[SIZE] = {18,35,36,61,9,112,77,12};double af[SIZE]={12.1, -23.8, 3.7, -16.0,9.1, 12.12, 7.7, 56.3};cout << "Before sorting:\n"<< "ai: \t";displayArray(ai, SIZE);sortArray(ai, SIZE);cout << "After sorting:\n"<< "ai: \t";displayArray(ai, SIZE);cout <<"Before sorting:\n"<< "af: \t";displayArray(af, SIZE);sortArray(af, SIZE);cout <<"After sorting:\n"<< "af: \t";displayArray(af, SIZE);return 0; }執行結果:
Before sorting: ai: 18 35 36 61 9 112 77 12 After sorting: ai: 9 12 18 35 36 61 77 112 Before sorting: af: 12.1 -23.8 3.7 -16 9.1 12.12 7.7 56.3 After sorting: af: -23.8 -16 3.7 7.7 9.1 12.1 12.12 56.3 #include <iostream> using namespace std; template<typename T> void Swap(T &a, T &b){T temp = a;a = b;b = temp; } int main(){//交換 int 變量的值int a1 = 10, a2 = 20;Swap(a1, a2);cout<<"交換int變量的值:"<<a1<<", "<<a2<<endl;//交換 float 變量的值float b1 = 1.5, b2 = 2.5;Swap(b1, b2);cout<<"交換float變量的值:"<<b1<<", "<<b2<<endl;//交換 char 變量的值char c1 = 'A', c2 = 'B';Swap(c1, c2);cout<<"交換char變量的值:"<<c1<<", "<<c2<<endl;//交換 bool 變量的值bool d1 = false, d2 = true;Swap(d1, d2);cout<<"交換bool變量的值:"<<d1<<", "<<d2<<endl;return 0; }執行結果:
交換int變量的值:20, 10 交換float變量的值:2.5, 1.5 交換char變量的值:B, A 交換bool變量的值:1, 0重載函數模板
C++語言允許一個函數模板可以使用多個模板參數或者重載一個函數模板。
用戶可以用非模板函數重載一個同名的函數模板
類模板
類模板:將類定義中的數據類型參數化。
類模板實際上是函數模板的推廣,可以用相同的類模板來組建任何類型的對象集合。
類模板的定義
template <類型形參表> class <類名> { //類說明體 };template <類型形參表> <返回類型> <類名> <類型名表>::<成員函數1>(形參表) { //成員函數定義體 };template <類型形參表> <返回類型> <類名> <類型名表>::<成員函數2>(形參表) { //成員函數定義體 }; ··· template <類型形參表> <返回類型> <類名> <類型名表>::<成員函數n>(形參表) { //成員函數定義體 };類模板的示例
#include <iostream> using namespace std;template<class ElementType> class Stack { public:Stack( int = 8 ); // 省缺棧元素的樹數目為8~Stack(){ delete [] data; }int pop(ElementType &num);int push(ElementType num); private:ElementType *data; //棧數據存儲int memNum; //棧元素個數int size; //棧大小 };template<class ElementType> Stack<ElementType>::Stack(int s) {size = s > 0 ? s : 8;data = new ElementType[size];memNum = 0; }template<class ElementType> int Stack<ElementType>::pop (ElementType &num) {if (memNum==0)return 0;num = data[ -- memNum ];return 1; }template<class ElementType> int Stack<ElementType>::push (ElementType mem){if (memNum == size)return 0;data[ memNum ++ ] = mem;return 1; }int main() {Stack<double> doubleStack(6);double f = 3.14;cout<<"Pushing elements into doubleStack:\n";while (doubleStack.push(f)){cout << f << ' ';f += f;}cout << "\nStack is full. Cannot push " << f << " onto the doubleStack.";cout<<"\nPopping elements from doubleStack:\n";while (doubleStack.pop(f))cout<<f<<' '; }執行結果:
Pushing elements into doubleStack: 3.14 6.28 12.56 25.12 50.24 100.48 Stack is full. Cannot push 200.96 onto the doubleStack. Popping elements from doubleStack: 100.48 50.24 25.12 12.56 6.28 3.14派生類模板
通過繼承可以產生派生類。
通過繼承同樣可產生派生的類模板。
幾種不同的派生:①從一般類派生出類模板;②從類模板中派生出類模板
從一般類派生出類模版
一般類(其中不使用類型參數的類)作基類,派生出類模板(其中要使用類型參數)。
基本語法:
class CB { //CB 為一般類... }; template <class T> class CA:public CB { //被派生出的CA 為類模板,使用了類型參數TT t; //私有數據為T 類型的 public:... };從類模版派生出類模版
類模板作基類,派生出新的類模板。但僅基類中用到類型參數T(而派生的類模板中不使用T)。
基本語法:
template <class T> class CB { //CB 為類模板T t; //私有數據為T 類型的 public:T gett(){ //用到類型參數T return t; } ... }; template <class T> class CA:public CB<T> {//CA 為類模板,其基類CB 為類模板 //將被“傳遞”給基類CB,本派生類中并不使用該類型參數T double t1; //私有數據成員 ... };類模板作基類,派生出新的類模板,且基類與派生類中均使用同一個類型參數T。
template <class T> class CB { //CB 為類模板(其中使用了類型參數T),它將作為類模板CA 的基類T t; //數據成員為T 類型的 public:T gett(){ //用到類型參數Treturn t;} ... }; template <class T> class CA:public CB<T> { //CA 為類模板,其基類CB 也為類模板。注意,類型參數T 將被“傳遞”給基類CB;本派生類中也將使用這同一個類型參數T T t1; //數據為T 類型的 public: ...};類模板作基類,派生出新的類模板,但基類中使用類型參數T2,而派生類中使用另一個類型參數T1(而不使用T2)。
template <class T2> class CB { //CB 為類模板(其中使用了類型參數T2),它將作為類模板CA 的基類T2 t2; //數據為T2 類型的 public: ... }; template <class T1, class T2>class CA:public CB<T2> { //CA 為類模板,其基類CB 也為類模板。注意,類型參數T2 將被“傳遞”給基類CB;本派生類中還將使用另一個類型參數T1 T1 t1; //數據為T1 類型的 public: ... };類模板繼承示例
#include <iostream> using namespace std;class CMyString:public basic_string<char> { public:void Trim();void LTrim();void RTrim();CMyString();CMyString(const char *s); };void CMyString::LTrim(){string::size_type len;if ((len=this->size())==0){return;}this->erase(0,this->find_first_not_of(" \t",0)); }void CMyString::RTrim(){string::size_type len;if ((len=size())==0){return;}this->erase(this->find_last_not_of(" \t")+1); }CMyString::CMyString():basic_string<char>() { } CMyString::CMyString(const char *s):basic_string<char>(s) { } void CMyString::Trim(){LTrim();RTrim(); } int main(){CMyString str1("\t Hello World ");str1.Trim();cout<<str1<<endl;return 0; }執行結果:
Hello World派生類和模板
為了運行的效率,類模板是相互獨立的,即獨立設計,沒有使用繼承的思想。對類模板的擴展是采用適配子(adapter)來完成的。通用性是模板庫的設計出發點之一,這是由泛型算法和函數對象等手段達到的。
派生類的目標之一也是代碼的復用和程序的通用性,最典型的就是MFC,派生類的優點是可以由簡到繁,逐步深入,程序編制過程中可以充分利用前面的工作,一步步完成一個復雜的任務。
模板追求的是運行效率,而派生追求的是編程的效率。
總結
以上是生活随笔為你收集整理的复习笔记(八)——C++模板的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 复习(一)—— Shell基本编程
- 下一篇: 复习笔记(九)——C++中的容器(STL