一、函数模板 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 |
函数模板和类模板
最新推荐文章于 2024-05-10 08:48:58 发布
函数模板和类模板