泛型编程(Generic Programming,简称GP)---模板
来源:互联网 发布:coc飞龙升级数据 编辑:程序博客网 时间:2024/04/29 14:31
泛型就是通过参数化类型来实现在同一份代码上操作多种数据类型。利用“参数化类型”将类型抽象化,从而实现灵活的复用。
C++引入模板的概念,主要包括函数模板和类模板
1、函数模板
1.1 函数模板定义及其实例化
求两个数中的大者,分别考虑整数、长整数、实数的情况
如果没有采用模板,一般用函数重载,如下:
#include <iostream>using namespace std;int Max(int x,int y) //整数比较 { return x>y? x:y ; } //长整数比较long Max(long x, long y) { return x>y? x:y ; }double Max(double x, double y) //实数比较{ return x>y? x:y ; }int main(){ int a=12,b=34,m; long c=67890,d=67899,n; double e=12.34,f=56.78,p; m=Max(a,b); n=Max(c,d); p=Max(e,f) ; cout<< "int_max="<<m<<endl; cout<< "long_max="<<n<<endl; cout<< "double_max="<<p <<endl ; return 0;}
程序运行结果如下:
int_max=34
long_max=67899
double_max=56.78
如果采用函数模板,只需写一次即可#include <iostream>using namespace std;template <class T>T Max(T x,T y ) { return x>y? x:y ; }int main(){ int a=12,b=34,m; long c=67890,d=67899,n; double e=12.34,f=56.78,p; m=Max(a,b);//调用函数模板,此时T被int取代 n=Max(c,d); //调用函数模板,此时T被long取代 p=Max(e,f) ; //调用函数模板,此时T被double取代 cout<< "int_max="<<m<<endl; cout<< "long_max="<<n <<endl; cout<< "double_max="<<p <<endl ; return 0; }
template <typename T>
int a;//错误,不允许在此位置有任何语句
T Max(T x,T y){ … }
即函数模板--->实例化----->模板函数。
例如,在程序中,当编译器遇到
template <typename T>
T Max(T x,T y){ … }
时,并不会产生任何代码,但当它遇到函数调用Max(a,b),编译器会将函数名Max与模板Max相匹配,将实参的类型取代函数模板中的虚拟类型T,生成下面的模板函数:
1.2 模板参数的匹配问题
C++在实例化函数模板的过程中,只是简单地将模板参数替换成调用实参的类型,并以此生成模板函数,不会进行参数类型的任何转换。这种方式与普通函数的参数处理有着极大的区别,在普通函数的调用过程中,C++会对类型不匹配的参数进行隐式的类型转换
#include <iostream>using namespace std;template <typename T1,typename T2>T1 Max(T1 x,T2 y){ return x>y? x:y ; }int main(){cout<<"2,2.3两数中的大者为:"<<Max(2,2.3)<<endl;cout<<" 'a',2 两数中的大者为:"<<Max('a', 2)<<endl;return 0; }
#include <iostream>using namespace std;template <typename T,int size> void BubbleSort(T a[]){ int i,j; bool change; for(i=size-1,change=true;i>=1 && change;--i) { change=false; for( j=0;j<i;++j) if(a[j]>a[j+1]) { T temp; temp=a[j];a[j]=a[j+1];a[j+1]=temp; change=true; } } }int main(){ int a[]={9,7,5,3,1,0,2,4,6,8}; char b[]={'A','C','E','F','D','B','U','V','W','Q'}; int i; cout<<"********a数组********"<<endl; cout<<"排序前:"<<endl; for(i=0;i<10;i++) cout<<a[i]<<" "; cout<<endl; BubbleSort<int,10>(a); cout<<"排序后:"<<endl; for(i=0;i<10;i++) cout<<a[i]<<" "; cout<<endl;cout<<"********b数组********"<<endl;cout<<"排序前:"<<endl;for(i=0;i<10;i++) cout<<b[i]<<" ";cout<<endl;BubbleSort<char,10>(b); cout<<"排序后:"<<endl;for(i=0;i<10;i++) cout<<b[i]<<" ";cout<<endl;return 0;}
程序运行结果如下:
********a数组********
排序前:
9 7 5 3 1 0 2 4 6 8
排序后:
0 1 2 3 4 5 6 7 8 9
********b数组********
排序前:
A C E F D B U V W Q
排序后:
A B C D E F Q U V W
1.4 函数模板重载
char *Max(char *x,char *y)
{ cout<<"This is the overload function with char*,char*!maxis:";
return strcmp(x,y)>0?x:y;
}
优先处理重载函数,如果没有重载函数匹配,然后在处理模板的实例化。
编写求2个数、3个数和一组数中最大数的函数模板。
#include <iostream>#include <string>using namespace std;template <typename T> //声明函数模板T Max(T x,T y) { return x>y? x:y; } template <typename T> //函数模板重载T Max(T x,T y,T z){ if(x<y) x=y; if(x<z) x=z; return x; } template <typename T> //函数模板重载T Max(T a[],int n) //求数组a[n]中的最大数{ T temp=a[0]; for(int i=1;i<n;i++) if (temp<a[i]) temp=a[i]; return temp;}int main(){ string s1="Beijing 2008",s2="Welcome to Beijing!"; int a[]={1,2,3,4,5,6,7,8,9}; cout<<Max(2,3)<<endl; cout<<Max(2.02,3.03,4.04)<<endl; cout<<Max(s1,s2)<<endl; cout<<Max(a,9)<<endl; return 0;}2、类模板
template<classT1,classT2 , … >
class类名
{
类体
} ;
class 也可以用 typename 代替//Stack.hconst int SSize=10; //SSize为栈的容量大小template <class T > //声明类模板,T为类型参数class Stack{public: Stack(){top=0;} void Push(T e); //入栈操作 T Pop(); //出栈操作 bool StackEmpty(){return top==0;} bool StackFull(){ return top==SSize;} private: T data[SSize]; //栈元素数组,固定大小为SSize int top; //栈顶指针};template <class T > //push成员函数的类外定义void Stack<T >::Push(T e){ if(top==SSize) { cout<<"Stack is Full!Don't push data!"<<endl; return; } data[top++]=e;}
template <class T> inline T Stack<T >::Pop(){ if(top==0) { cout<<"Stack is Empty!Don't pop data!"<<endl; return 0; } top--; return data[top];}
注意:在引用模板的类名的地方 必须伴有该模板的参数名表。如:void Stack<T>::Push(T e){ … }
class Stack{
public:
Stack(){top=0;}
void Push(int e); //入栈操作
int Pop(); //出栈操作
boolStackEmpty(){returntop==0;}//判断栈是否为空
boolStackFull(){return top==10;} //判断栈是否已满
private:
int data[10];
int top; //栈顶指针
};
类模板、模板类及模板对象之间的关系图
类模板名<实际类型名表> 对象名;
类模板名<实际类型名表> 对象名(实参表);
由类模板创建其实例模板类时,必须为类模板的每个模板参数显式指定模板实参。然而由函数模板创建其实例模板函数时,可以不显式指定模板实参,这时编译器会自动根据函数调用时的实参来推断出Stack<int> int_stack;
for(int i=1;i<10;i++) int_stack.Push(i);
return 0 ;
2.2.1 非类型参数
//Stack.htemplate <class T,int SSize>class Stack{public: Stack(){top=0;} void Push(T e); //入栈操作 T Pop(); //出栈操作 bool StackEmpty(){return top==0;} bool StackFull(){ return top=SSize;} private: T data[SSize]; //栈元素数组,固定大小为SSize int top; //栈顶指针};//Push成员函数的类外定义 template <class T,int SSize>void Stack<T,SSize>::Push(T e){ if(top==SSize) { cout<<"Stack is Full!Don't push data!"<<endl; return; } data[top++]=e;}// Pop成员函数的类外定义,指定为内联函数template <class T,int SSize> inline T Stack<T,SSize>::Pop(){ if(top==0) { cout<<"Stack is Empty!Don't pop data!"<<endl; return 0; } top--; return data[top];}
template<class T,int SSize=10>
class Stack
{public:
…
private:
Tdata[SSize];//栈元素数组,固定大小为SSize
int top; //栈顶指针
};
template<class T=int,int SSize=10>
classStack
{public:
…
private:
T data[SSize];//栈元素数组,固定大小为SSize
int top; //栈顶指针
};
Stack<> mystack; //same as Stack<int,10>
模板类型的模板参数类模板的模板形参表中的参数类型有3种:类型参数、非类型参数、类模板类型的参数,函数模板的模板参数类型也与此相同。下面看一个类模板类型的模板参数的例子。
类模板类型的模板参数举例
#include <iostream>using namespace std;template <class T,size_t size>class Array{ T data[size]; size_t count; //数组元素个数public: Array(){count=0;} //构造函数 void PushBack(const T& t) { if(count<size) data[count++]=t; } void PopBack() { if(count>0) - -count; } T* Begin(){return data;} T* End(){return data+count;} };
//声明Container类模板,//它有一个类模板类型的模板参数Seqtemplate <class T,size_t size,template <class,size_t> class Seq>class Container{ Seq<T,size> seq;public: void Append(const T& t){ seq.PushBack(t);} T* Begin(){return seq.Begin();} T* End(){return seq.End();}};
int main(){ const size_t N=10; container<int,N,Array> container; container.Append(1); container.Append(2); int *p=container.Begin(); while(p!=container.End()) cout<<*p++<<endl; return 0;}
- 泛型编程(Generic Programming,简称GP)---模板
- Part7 模板与泛型编程 Templates and Generic Programming
- Part7 模板与泛型编程 Templates and Generic Programming
- C#泛型编程(Generic Programming)
- (Effective C++)第七章 模板与泛型编程 (Templates and Generic Programming)
- Part7 模板与泛型编程 Templates and Generic Programming(二)
- [翻译] Effective C++, 3rd Edition, Chapter 7. Templates(模板)和 Generic Programming(泛型编程)
- 什么是泛型编程——Generic Programming
- Java中的泛型编程(generic programming)和泛型类(generic class)
- effective C++ 学习(Templates and Generic Programming(泛型编程))
- Extreme Programming(极限编程,简称XP)
- C++——OOP(Object-Oriented Programming) vs. GP(Generic Programming)
- 产生式编程(Generative Programming,GP)
- Generic Programming
- 什么是Extreme Programming(极限编程,简称XP)
- 什么是Extreme Programming(极限编程,简称XP)
- 什么是Extreme Programming(极限编程,简称XP)
- 编程日记: 学习:Generic<Programming>:简化异常安全代码
- 行内元素与块级元素
- UVA 10034 - Freckles
- 九度oj-1384-二维数组中的查找
- 华为海思的麒麟950到底新在哪儿?
- 使用Git上传项目代码到github
- 泛型编程(Generic Programming,简称GP)---模板
- 员工离职停用ebs账号时,需要检查的内容
- (学习)C++ Primer(1)
- iOS开发——网络连接判断
- jsp清空input
- 解决firefox页面刷新后退,按钮禁用状态无法恢复
- SpringMVC响应结果的生成
- 1295: [SCOI2009]最长距离
- thinkphp 3.2 =》0625-2_ =>css/js /mages路径