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
一、函数模板
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
相关文章推荐
- C++ 函数模板一(函数模板定义)
- [置顶] C++(函数模板的覆盖 包括:处理私有类的函数模板覆盖)
- C++的函数模板和类模板理解
- c++的函数模板和类模板
- c++远征之模板篇——函数模板、类模板
- C++学习日记6——模板篇的函数模板和类模板
- C++ 模板学习 函数模板、类模板、迭代器模板
- C++的函数模板与类模板
- C++ 函数模板,类模板初步认识
- C++库研究笔记——使用函数模板还是类模板?+ 一个类型重复问题的两种解决方法
- C++ 类模板作为函数模板示例
- c++ 模板学习笔记:类模板和函数模板实现pair(权哥)
- C++模板简单分析与举例
- 大整数类BIGN的设计与实现 C++高精度模板
- C++学习之模板编程:可变参数模板
- c++写模板的注意事项
- C++学习——模板与异常处理
- 漫谈C++为什么不支持模板虚函数
- c++模板类(一)理解编译器的编译模板过程
- 从C++到objective-c----委托(模板方法)