模板
定义:模板是一个将数据类型参数化的工具,它把“一般的算法”和其“对数据类型的实现”区分开来。
模板可以分为函数模板和类模板。
采用模板的方式定义函数或类时不确定某些函数参数或数据成员的类型,而将它们的数据类型作为模板的参数,在使用模板时根据实参的数据类型确定模板参数(数据类型)的数据类型。
函数模板
函数模板可以用来创建一个通用功能的函数,以支持多种不同形参,进一步简化重载函数的函数体设计。
声明方法:template <class(或typename) 标识符>
函数声明
函数重载和函数模板
函数模板扩展了函数重载,利用函数重载可以让多个函数共享一个函数名,只要重载函数的参数类型必须有所不同,但是由于参数的类型不一样,虽然这些函数所完成的功能完全一样,也必须为每一个重载函数编写代码。
一个函数模板可以用来生成多个功能相同但参数和返回值的类型不同的函数。
<span style="font-size:18px;">#include <iostream>
using namespace std;
template <class T>//定义的模板
T abs(T val)//定义一个可以对任何类型求绝对值的函数模板
{
return val<0?-val:val;
}
int main()
{
int a=10;
cout<<abs(a)<<endl;//类型参数T替换为int
double b=-12;
cout<<abs(b)<<endl;//类型参数T替换为double
float c=-10.12F;
cout<<abs(c)<<endl;//类型参数T替换为float
return 0;
}</span>
程序分析:输出的结果为10,12,10.12
编译器从调用abs()时实参的类型,推导出函数模板的类型参数。例如对于调用表达式abs(a),由于实参a为int型,所以推导出模板中类型参数T为int型。当类型参数的含义确定后,编译器将以函数模板为样板,生成一个函数:
<span style="font-size:18px;">int abs(int val)
{
return val<0?-val:val;
}</span>
模板的定义以关键字template开头,关键字class后面的标识符T由用户自定义类型,称为类型参数,是函数模板abs()中没有确定数据类型的参数val的类型,模板定义的下面是模板函数abs()的定义。
定义函数模板是可以使用多个类型参数,每个类型参数前面只需加上关键字class,用逗号分隔。
template <class T1,class T2>
T1 max(T1 x,T2 y)
{ return x>=y?x:(T1)y; }
函数模板的实例化
函数模板将数据类型参数化,这使得在程序中能够用不同类型的参数调用同一个模板函数,在调用模板函数时即创建函数模板的一个实例,这个过程称为函数模板的实例化。
函数模板的实例化由编译器完成,编译时函数模板本身并不产生可执行代码,只有在函数模板被实例化时,编译器才按照实参的数据类型进行类型。参数的替代,生成新的函数。
类模板
定义:为了起到模板的作用,与函数模板一样,定义一个类模板时,必须将某些数据类型作为类模板的类型参数。模板类的实现代码与普通类没有本质上的区别,只是在定义其成员时要用到类模板的类型参数。
类模板和函数模板
类模板实际上是函数模板的推广,它是一种不确定的类的某些数据成员的类型或是成员函数的参数及返回值的类型的类。函数模板只能用于定义非成员函数,它是模板的一个特例。
类模板和类
类是对问题的抽象,而类模板是对类的抽象,即更高层次的抽象。类模板为带参数(或参数化)的类,它可以用来生成多个功能相同而某些数据成员类型不同或成员函数的参数及返回值的类型不同的类。
<span style="font-size:18px;">template <class T>//模板
class MyClass//定义的类模板
{
private:
T x;//声明参数T用于声明数据类型
public:
void Setx(T a)//类型参数T用于声明成员函数的参数
{ x-a; }
T Getx()//类型参数T用于声明成员函数的返回值
{ return x; }
};</span>
在模板类的外部定义模板类的成员函数时,必须用如下的形式:
template <class T>不能省略模板声明
void MyClass <T> ::Setx(T a)
{ x=a; }
类模板的实例化
与函数模板不同,类模板不是通过调用函数时实参的数据类型来确定类型参数具体所代表的类型,而是通过在使用模板类时声明对象时所给出的实际类型数据确定类型参数。
使用一个类模板使用一个类型参数为int的模板类的对象:MyClass <int> intObject 对于这个对象的声明,编译器首先用int替代类模板定义中的类型参数T,生成一个所有数据类型已确定的类class。然后再利用这个类创建对象intObject。
含多个参数的类模板的定义:template <class T1,int i,class T2>
class MyClass
{ ... }
则声明模板类的对象应采用这样的形式:MyClass <int,100,float> MyObject
<span style="font-size:18px;">#include <iostream>
using namespace std;
template <class T1,class T2>
class MyTemClass
{
private:
T1 x;
T2 y;
public:
MyTemClass(T1 a,T2 b)
{ x=a;y=b; }
void ShowMax()
{ cout<<"MaxMember="<<(x>=y?x:y)<<endl; }
};
int main()
{
int a=10;
float b=12.45F;
MyTemClass<int float> mt(a,b);
mt.ShowMa();
return 0;
}</span>
输出的结果为:MaxMember=12.45.