C++模板

来源:互联网 发布:废除网络中立 编辑:程序博客网 时间:2024/06/05 04:29

有以下这样3个比大小的函数:

int max(int x,int y){      return x+y; }   double max(double x,double y) {     return x+y; } long max(long x,long y){     return x+y;}
它们拥有同一个函数名,相同的函数体,却因为参数类型和返回值类型不一样,所以是3个完全不同的函数。即使它们是二元重载函数,但是不得不为每一函数编写一组函数体完全相同的代码。如果从这些函数中提炼出一个通用函数,而它又适用于多种不同类型的数据,这样会使代码的重用率大大提高。那么C++的模板就可解决这样的问题。模板可以实现类型的参数化(把类型定义为参数),从而实现了真正的代码可重用性。C++中的模板可分为函数模板和类模板,而把函数模板的具体化称为模板函数,把类模板的具体化成为模板类。

函数模板

函数模板就是建立一个通用的函数,其参数类型和返回类型不具体指定,用一个虚拟的类型来代表。函数模板的声明格式;template<typename 类型参数>  返回类型 函数名(模板形参表)  {    函数体  }  或  template<class 类型参数>  返回类型 函数名(模板形参表)  {    函数体  }

template是一个声明模板的关键字,类型参数一般用T这样的标识符来代表一个虚拟的类型,当使用函数模板时,会将类型参数具体化。typename和class关键字作用都是用来表示它们之后的参数是一个类型的参数。只不过class是早期C++版本中所使用的,后来为了不与类产生混淆,所以增加个关键字typename。下面我就对上述3个函数进行函数模板化:
#include<iostream>using namespace std;template <class T> T getmax(T a,T b){return (a>b)?a:b;} int main(){int i=5,j=7,k;double a=2.5,b=1.5,c;k=getmax(i,j);c=getmax(a,b);cout<<k<<endl;cout<<c<<endl;return 0;}

当调用函数模板时(如:max(10,10))就是对函数模板的具体化(如:int max(int,int)),具体化的函数模板就是模板函数。在函数模板中类型参数也可以指定多个,只不过定义的每个类型参数之前都必须有关键字typename(class)。

#include "stdafx.h"#include <iostream>using namespace stdtemplate <typename T1,typename T2>//多类型参数的函数模板T1 max(T1 x,T2 y){    return x+y;}int main(){    int x=10;    double y=10.10;    cout<<max(x,y)<<endl;//相当于调用函?数int Add(int,double)    cout<<max(y,x)<<endl;//相当于调用函数double Add(double,int)    return 0;}

在定义函数模板时要注意的一点是在template语句和函数模板定义语句之间是不允许插入其他的语句的。和一般函数一样,函数模板也可以重载:

/*函数模板重载*/#include<iostream>using namespace std;template <class T> T getsum(T a,T b){return (a+b);} //重载template <class T> T getsum(T a,T b,T c){return (a+b+c);} int main(){int i=5,j=7,k;double a=2.5,b=1.5,c=3.5,d;k=getsum(i,j);d=getsum(a,b,c);cout<<k<<endl;cout<<d<<endl;return 0;}

函数模板与同名非模板函数也可以重载。比如:

/*函数模板与非模板函数重载*/#include<iostream>using namespace std;template <class T> T getsum(T a,T b){return (a+b);} //重载int getsum(int a,int b,int c){return (a+b+c);} int main(){int i=5,j=7,k;double a=2,b=1,c=3,d;k=getsum(i,j);d=getsum(a,b,c);cout<<k<<endl;cout<<d<<endl;return 0;}

当模板函数和同名的非模板函数重载时,首先寻找与参数类型完全匹配的非模板函数,找到了,则调用它,如果没找到,则寻找函数模板,找到后具体化函数模板,而后调用该模板函数。


类模板

和函数模板一样,类模板就是建立一个通用类,其数据成员的类型、成员函数的返回类型和参数类型都不具体指定,用一个虚拟类型来代表。当使用类模板建立对象时,系统会根据实参的类型来取代类模板中的虚拟类型从而实现不同类的功能。其定义格式为:

template <typename 类型参数>  class 类名  {    类成员声明  }  或  template <class 类型参数>  class 类名  {    类成员声明  }

而类模板定义对象的形式:

  类模板名<实际类型> 对象名;

  类模板名<实际类型> 对象名(实参);

示例说明如下:

/*类模板*/#include <iostream>#include <string>using namespace std; template <typename T>//在类模板定义之前,都需要加上模板声明class BinaryOperation//二目运算类{    private:        T x; T y;       char op;        void add()        {            cout<<x<<op<<y<<"="<<x+y<<endl;        }        void sub()        {            cout<<x<<op<<y<<"="<<x-y<<endl;        }        void mul();        void div();        public:        BinaryOperation(T x,T y):x(x),y(y)    //调用构造函数时,利用初始化清单x(x),y(y)给对象的私有成员变量赋值,        {//x=x1;//y=y1;        }        void determineOp(char op);};//在类外定义成员函数://在成员函数定义之前进行模板声明,//且在成员函数名之前加上"类类名<类型参数>::"template <typename T>void BinaryOperation <typename T>::mul(){    cout<<x<<op<<y<<"="<<x*y<<endl;}template <typename T>void BinaryOperation <typename T>::div(){        cout<<x<<op<<y<<"="<<x/y<<endl;}template <typename T>void BinaryOperation <typename T>::determineOp(char op){    this->op=op;    switch(op)    {        case '+':            add();            break;        case '-':            sub();            break;        case '*':            mul();            break;        case '/':            div();            break;        default:            break;    }}int main(){    BinaryOperation<int> op(10,10);    //调用构造函数生成op时,顺便给对象op的成员变量赋值,    op.determineOp('+');    op.determineOp('-');    op.determineOp('*');    op.determineOp('/');    return 0;}



0 0
原创粉丝点击