C++中函數模板和類模板

轉自:http://hi.baidu.com/gamedot/item/a10da895e32586b9cc80e5dd

一、函數模板

1.1、模板函數含有類型參數

template <class T>

T MyMin(T a,T b){

     return a<b?a:b;

}

void main()

{

     cout<<MyMin(23,21)<<endl;//OK 模板參數爲int

     cout<<MyMin(2.0,2.123)<<endl;//OK 模板參數爲double

//     cout<<MyMin(2,2.123)<<endl;//error 模板參數不明確

     cout<<MyMin<double>(2,2.123)<<endl;//OK 模板參數爲double

     cout<<MyMin<int>(2,2.123)<<endl;//OK 模板參數爲int,但有警告

}

注1:這裏的關鍵詞class可用關鍵詞typename替換。

1.2、模板函數含有非類型參數

template <class T,int size>

T MyMin(T(&array)[size])

{

     int i=size-1;

     T minValue=array[i-1];

     while(i>0)

          minValue=minValue>array[--i]?array[i]:minValue;

     return minValue;

}

void main()

{

     int ars[]={20,2,1,-3,4,5,9};

     cout<<MyMin(ars)<<endl;

}

注2:在上例中,編譯器解析出的T爲int,size爲7。如果是

void main()

{

     int ars[20]={20,2,1,3,4,5,9};

     cout<<MyMin(ars)<<endl;

}

則編譯器解析出的size是20,而不是7,從而輸出的是0,而不是1。

注3:對於下面的代碼,在VC中解析不出T的類型

void main()

{

     int* ars=new int[20];

     //…

     cout<<MyMin(ars)<<endl;

}

對於此代碼,編譯器報錯

error C2784: “T MyMin(T (&)[size])”: 未能推導出“T1 (&)[size]”(從“int *”中)的模板參數

1.3 函數模板可以含有多個類型參數

template <class T1,class T2 >

void MyFunc(T1 obj1,T2 obj2){

     //…

}

1.4模板顯式特化

考察代碼段:

1    template <class T>

2    T MyMin(T a,T b){

3         return a<b?a:b;

4    }

11   void main(){

12        char*a="14";

13        char*b="21";

14        cout<<MyMin(a,b)<<endl;

14   }

其輸出結果可能是”21”而不是我們所希望的”12”。但是,若將下面的代碼加到main函數之前,則就會得到我們所希望的結果。

5    template<> char*MyMin(char*a,char*b){

6         if(strcmp(a,b)<0)

7              return a;

8         else

9              return b;

10   }

當程序中沒有第5到10行代碼時,第14行代碼調用第1到4行中的代碼,其結果得到的是字符串指針的值的最小者,而不是真正的字符串值最小者。當有了第5到10行代碼之後,第14行代碼調用的就是第5到10行代碼,這時得到的纔是字符串值最小者。對於此函數的其他調用依然執行第1到4 行代碼。這就是所謂的模板顯式特化。

1.5 STL中許多函數模板

       可以這樣說,C++編譯器中的所有函數都是模板。下面我們介紹幾個重要的、常用函數模板:

1)求兩者中的最大與最小元max與min    ;

2)交換兩者的值swap ;

3)排序函數sort       ;

#include <algorithm>

using namespace std;

void main(){

     int a[]={12,3,2,4,5,6,8,7};

     sort(a,a+8);

}

這裏,sort可接受任何類型的參數,只要該類型時刻排序的。從上面的使用可以看出,傳給此函數的是一塊連續地址的首地址和尾地址。

4)合併函數merge

#include <algorithm>

void main(){

     int a[]={12,3,2,4,5,6,8,7};

     int b[]={14,13,11,1,15,19,18};

     int c[20]={0};

     sort(a,a+8);//a=2 3 4 5 6 7 8 12

     sort(b,b+7);//b=1 11 13 14 15 18 19

     merge(a,a+8,b,b+7,c);//c=1 2 3 4 5 6 7 8 11 12 13 14 15 18 19

}

5)求和函數accumulate

#include <algorithm>

#include <numeric>

#include <functional>

using namespace std;

struct MyOp : public binary_function <int, int, int>

{

      int operator()(const int& _Left, const int& _Right) const;

};

int MyOp::operator ()(const int& _Left, const int& _Right) const{

     return _Left*_Right;

}

void main()

{

     int a[]={12,3,2,4,5,6,8,7};

     int result=accumulate(a,a+8,0);//求和,開始時值爲0,和爲47

     result=accumulate(a,a+8,1,MyOp());//求積,開始時值爲1,積爲483840

}

6)初始化函數fill與generate

       一般的C/C++編譯器都提供了一個初始化內存塊的函數,memset,其使用方式如下:

#include <memory.h>

#include <stdio.h>

int main( void )

{

   char buffer[] = "This is a test of the memset function";

   printf( "Before: %s\n", buffer );

   memset( buffer, '*', 4 );

   printf( "After: %s\n", buffer );

}

它有一個缺點,就是隻能以字節爲單位賦初值。利用fill函數模板,可以多任意一塊連續地址用任一種數據類型進行初始化。其使用方法爲:

#include <algorithm>

using namespace std;

struct MyStruct{

     int a,b;

};

void main(){

     MyStruct v={1,1};

     MyStruct a[12];

     fill(a,a+12,v);

}

generate利用一個生成子給一個連續的地址塊賦值:

#include <algorithm>

using namespace std;

int gen(){

     static a=0;

     return ++a;

}

void main(){

     int a[12];

     generate(a,a+12,gen);

}

7)查找函數find

       在上例中,main函數退出之前加上語句

     int*p=find(a,a+12,4);

就可以體會查找函數的功效。

8)隨機調整數組的順序函數random_shuffle

#include <algorithm>

using namespace std;

int gen(){

     static a=0;

     return ++a;

}

void main(){

     int a[12];

     generate(a,a+12,gen);//a=1 2 3 4 5 6 7 8 9 10 11 12

     random_shuffle(a,a+12);//可能是阿=11 2 10 3 1 12 8 4 5 7 9 6

}

二、類模板

2.1類模板的定義

       一個簡單鏈表

template <class T>

class List{

protected:

     template <class T1>

     struct LNode{

         T1 data;

          LNode<T1>*next;

     };

     LNode<T>*head,*tail;

     int len;

public:

     List();

     virtual ~List();

     bool ClearList();

     bool InsertFirst(T e);

     bool DelFirst(T&e);

     bool Append(T e);

     bool Remove(T&e);

     bool InsBefore(int index,T e);

     bool InsAfter(int index,T e);

     bool Delete(int index,T&e);

     T& operator[](int index);

};

       從這個定義中可以看出,類模板的第一行有關鍵字template開始,其後面的一對尖括號中是模板類型。注意,這裏類模板中有嵌套的類模板。

2.2類模板的實現

template <class T>

List<T>::List(){

     head=tail=new LNode<T>;

     head->next=tail->next=0;len=0;

}

template <class T>

List<T>::~List(){

     LNode<T>*p=head->next;

     while(p){     LNode<T>*tmp=p->next;     delete p;     p=tmp;}

     delete head;

}

template <class T>

bool List<T>::ClearList(){

     LNode<T>*p=head->next;

     while(p){     LNode<T>*tmp=p->next;     delete p;     p=tmp;}

     tail=head;head->next=tail->next=0;len=0;

     return true;

}

template <class T>

bool List<T>::InsertFirst(T e){

     LNode<T>*p=new LNode<T>;

     if(!p)return false;

     p->data=e;p->next=head->next;head->next=p;

     if((len++)==0)tail=p;

     return true;

}

template <class T>

bool List<T>::DelFirst(T&e){

     if(len==0)return false;

     LNode<T>*p=head->next;

     e=p->data;head->next=p->next;

     if(tail==p)tail=head;

     delete p;     len--;

     return true;

}

template <class T>

bool List<T>::Append(T e){

     LNode<T>*p=new LNode<T>;

     if(!p)return false;

     p->data=e;

     if(len==0){

          head->next=p,p->next=0,tail=p,len++;

         return true;

     }

     tail->next=p,p->next=0,tail=p,len++;

     return true;

}

template <class T>

bool List<T>::Remove(T&e){

     if(len==0)return false;

     LNode<T>*p=head;

     while(p->next!=tail)p=p->next;

     p->next=0;

     delete tail;tail=p;len--;

     return true;

}

template <class T>

bool List<T>::Delete(int index,T&e){

     if(index<0||index>=len)return false;

     else if(index==0){

          LNode<T>*p=head->next;

          head->next=p->next;

          if(tail==p)tail=head;

         delete p;   len--;

         return true;

     }

     LNode<T>*p=head;

     int j=0;

     while(p->next&&j<index)p=p->next,j++;

     LNode<T>*q=p->next;p->next=q->next;

     if(tail==q)tail=p;

     len--;delete q;

     return true;

}

template <class T>

bool List<T>::InsBefore(int index,T e){

     if(index<0||index>=len)return false;

     LNode<T>*p=head;

     int j=0;

     while(p->next&&j<index)p=p->next,j++;

     LNode<T>*q=new LNode<T>;

     q->data=e;q->next=p->next;p->next=q;

     if(tail==p)tail=q;

     len++;

     return true;

}

template <class T>

bool List<T>::InsAfter(int index,T e){

     /*......*/

     return true;

}

template <class T>

T& List<T>::operator[](int index){

     if(index<0||index>=len)return head->data;

     int i=-1;

     LNode<T>*p=head;

     while(i<index)p=p->next,i++;

     return p->data;

}

2.3 類模板的應用

void main(){

     List<int> int_list;

     for(int i=0;i<10;i++)int_list.Append(i);

     cout<<int_list[3]<<endl;

}

輸出結果是:3



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章