您的位置:首页 > 编程语言 > C语言/C++

C++中函数模板和类模板

2012-12-17 14:46 281 查看
转自: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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: