在讲模板之前,先闲扯一下吧:C++最重要的特性之一就是,代码的重用,为了实现代码重用,代码就必须具有通用性。
通用代码不受数据类型的影响,并且可以自动适应数据类型的变化,这种程序设计类型称为参数化程序设计。
模板是C++支持参数化程序设计的工具,通过它可以实现参数化多态性。
所谓参数化多态性是指:将程序所处理的对象的类型参数化,使得一段程序可以处理多种不同类型的对象。
简单的理解,模板就是为了让代码的通用性更强。有了以上的理解, 下面理解函数模板和类模板就轻松多了。
(2)函数模板
要讲函数模板,就得先讲一讲函数重载,相信大家都知道,函数重载通常是对于不同的数据类型完成类似的操作。
在很多时候,一个算法其实是可以处理多种数据类型的。但是用函数实现算法时,即使设计为重载函数也只是
使用相同的函数名,函数体仍然要分别定义。下面举一个求绝对值的函数重载的实例,方便大家理解。
int abs(int x)
{
return x<0?-x:x;
}
double abs(double x)
{
return x<0?-x:x;
}
可以看出,这两个函数的功能和函数体是一模一样的,但是为了实现对不同数据类型的数据求绝对值操作,我们不得不写两个
同名函数来实现操作,如果能写一段通用代码适用与多种不同数据类型该多好呢,这会使代码的可重用性大大提高,从而提高
软件的开发效率。所以聪明的人们便设计出了这么一个工具,那就是函数模板,程序员只需对函数模板编写一次,然后基于调
用函数时提供的参数类型,C++编译器将自动产生相应的函数来正确处理该类型的数据。
函数模板的定义形式如下:
template<模板参数列表>
类型名 函数名(参数列表)
{
函数体的定义;
}
说明:class或者typename标识符,指明可以接收一个类型参数,这些类型参数代表的是类型,可以是系统预定义的数据类型,也
可以是自定义类型。类型参数可以用来指定函数模板本身的形参类型、返回值类型,以及声明函数中的局部变量。
下面举一个求绝对值的函数模板的程序。
#include<iostream>
using namespace std;
template<typename T>
T abs(T x)
{
return x<0?-x:x;
}
int main()
{
int n_number=-5;
double d_number=-5.5;
cout<<abs(n_number)<<ebdl;
cout<<abs(d_number)<<endl;
return 0;
}
运行结果如下:
在main函数中两次调用abs()函数,
对于调用表达式abs(n_number)时,由于n_number为int类型,所以推导出模板中类型参数T为int;
当调用表达式abs(d_number)时,由于d_number为double类型,所以推导出模板类型参数T为double;
当类型参数的含义确定后,编译器将以函数模板作为一个样板,生成一个函数,这一过程便是传说中的函数模板实例化;
其实编译器会实例化以下两个函数:
int abs(int x)
{
return x<0?-x:x;
}
double abs(double x)
{
return x<0?-x:x;
}
下面来一个稍微复杂一点的函数模板的例子,供各位深入理解一下函数模板的用法。
#include<iostream>
using namespace std;
template<class T>
void outputArray(const T *array,int count)
{
for(int i=0;i<count;i++)
{
cout<<array[i]<<" ";
}
cout<<endl;
}
int main()
{
const int a_count=8,b_count=8,c_count=20;
int a[a_count]={1,2,3,4,5,6,7,8};
double b[b_count]={1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8};
char c[c_count]="Welcome to see you!";
cout<<"数组a:"<<endl;
outputArray(a,a_count);
cout<<"数组b:"<<endl;
outputArray(b,b_count);
cout<<"数组c:"<<endl;
outputArray(c,c_count);
return 0;
}
运行效果如下图:
(3)类模板
类模板可以使用户为类定义一种模式,使得类中的某些数据成员、成员函数、返回值或者局部
变量能取任意类型。(包括系统预定义和用户自定义的)
如果说类是对一组对象公共性质的抽象,而类模板则是对不同类的公共性质的抽象,所以说类模板是更高层次的抽象。
类模板声明的语法形式:
template<模板参数表>
class 类名
{
类成员声明;
}
其中类成员的声明方法与普通类的声明方法其实是一模一样的,只是它的各个成员(数据成员和函数成员)通常要用到模板的类型参数T;
注意:如果要在类模板以外定义成员函数,要采用以下形式
template <模板参数表>
类型名 类名<模板参数标识符列表>::函数名(参数表)
一个类模板声明,它自身并不是一个类,它说明类的一个家族,只有当它被其它代码引用时,模板才根据需要生成具体的类。
使用一个模板类来建立对象时,格式如下:
模板名<模板参数表>对象名1,....对象名N;
下面举个例子,方便大家理解,
本例中,声明一个实现任意类型数据存取的类模板Store,然后通过具体数据类型参数对类模板进行实例化,
生成类,然后类再被实例化,
生成对象s1,s2,s3,d.
源程序如下:
运行结果: