C++函数模板的定义、使用和重载(附带实例)
所谓函数模板(function template),指的是建立一个通用函数,它所用到的数据类型(包括返回值类型、形参类型、局部变量类型)不具体指定,而是用一个虚拟类型代替(即使用一个标识符进行占位),发生函数调用时再根据传入的实参倒推出其真正类型。
函数模板是对函数功能框架的描述,不是一个实在的函数,编译器不能为其生成可执行代码。
实际开发中,通常将函数模板的定义分开写,分为模板头部分(即 template 部分)和函数名部分:
例如,定义一个求和的函数模板,计算两个数的和,代码如下:
定义函数模板后,可在程序中调用该函数模板。例如,下面的代码调用了 Sum() 函数模板:
如果采用如下形式调用 Sum() 函数模板,将会出现错误:
上述代码为 Sum() 函数模板传递了两个不同类型的参数,编译器会产生歧义。但如果调用函数模板时显式说明模板类型,就不会出现错误。例如:
用函数模板生成的实际可执行的函数称为模板函数。注意,“函数模板”与“模板函数”不是一个概念。函数模板是一个框架,它不是真正可以编译生成代码的程序;模板函数是把函数模板中的类型参数实例化后生成的函数,它和普通函数本质上是一样的,可以生成可执行代码。
与普通函数和类不同,函数模板或类模板在其他类作为友元之前必须先声明(不用定义,声明即可),否则无法通过编译。
可以定义如下函数模板:
调用 max() 即可得到两个整型数或两个浮点数中的最大值:
【实例】寻找最大值。定义函数模板 Max(),求解数组元素中的最大值。具体代码如下:
模板只作用于其下方的类或函数,所以在类外实现成员函数时要在函数前进行模板声明(即使函数没有用到该模板类型,类名里也要加上 <Type>)。
【实例】寻找最小值。先定义一个函数模板,功能是寻找两个数中的最小值;再重载该函数模板,寻找字符串中的最小值;最后在主函数中调用函数模板。具体代码如下:
函数模板是对函数功能框架的描述,不是一个实在的函数,编译器不能为其生成可执行代码。
C++函数模板的定义
函数模板的定义形式如下:template <类型形式参数表> 返回值类型 函数名(形式参数表) { 函数体 }
- 关键字 template 表示定义的是一个模板;
- 尖括号为该模板的类型形式参数表,不能为空,多个类型参数间用逗号隔开。
- 类型参数分为类型参数、非类型参数两种,类型参数使用关键字 class 或 typedef 开始,其后是一个用户定义的合法标识符;非类型参数与普通参数相同,通常为一个常数。
类型参数列表使用尖括号“< >”,形式参数列表使用圆括号“( )”,初学者要注意区分。
实际开发中,通常将函数模板的定义分开写,分为模板头部分(即 template 部分)和函数名部分:
template <class T> //模板头,注意这里不能有分号 void fun(T t) //定义函数模板 fun() { ... }
例如,定义一个求和的函数模板,计算两个数的和,代码如下:
template <class type> //模板头,type 表示待求和两个数的数据类型 Type Sum(type xvar, type yvar) //定义函数模板 Sum() { return xvar + yvar; }
定义函数模板后,可在程序中调用该函数模板。例如,下面的代码调用了 Sum() 函数模板:
int iret = Sum(10,20); //调用 Sum()函数模板,计算两个整数的和 double dret = Sum(10.5,20.5); //调用 Sum()函数模板,计算两个实数的和
如果采用如下形式调用 Sum() 函数模板,将会出现错误:
int iret = Sum(10,5,20); //错误调用,传递了两个不同类型的参数 double dret = Sum(10,20.5); //错误调用,传递了两个不同类型的参数
上述代码为 Sum() 函数模板传递了两个不同类型的参数,编译器会产生歧义。但如果调用函数模板时显式说明模板类型,就不会出现错误。例如:
int iret = Sum<int>(10,5,20); //正确调用,使用<int>显式说明 double dret = Sum<double>(10,20.5); //正确调用,使用<double>显式说明
用函数模板生成的实际可执行的函数称为模板函数。注意,“函数模板”与“模板函数”不是一个概念。函数模板是一个框架,它不是真正可以编译生成代码的程序;模板函数是把函数模板中的类型参数实例化后生成的函数,它和普通函数本质上是一样的,可以生成可执行代码。
与普通函数和类不同,函数模板或类模板在其他类作为友元之前必须先声明(不用定义,声明即可),否则无法通过编译。
C++函数模板的使用
假设要通过函数求解两个数中最大的数,且这两个数的类型不确定,可能是整型数,也可能是浮点数。可以定义如下函数模板:
template <class Type> //模板头,type 表示待比较两个数的数据类型 Type max(Type a, Type b) //定义函数模板 max() { if(a > b) return a; else return b; }
调用 max() 即可得到两个整型数或两个浮点数中的最大值:
cout << "最大值:" << max(10,1) << endl;cout << "最大值:" << max(200.05,100.4) << endl;
【实例】寻找最大值。定义函数模板 Max(),求解数组元素中的最大值。具体代码如下:
#include <iostream> using namespace std; template <class type,int len> //模板头,type 表示数组类型,len 表示元素个数 Type Max(type array[len]) //定义函数模板 Max() { type ret = array[0]; //定义变量 ret,初始化为数组第 1 个元素的值 for(int i=1;i<len;i++) //遍历数组元素 { ret = (ret > array[i])? ret : array[i]; //条件运算,比较相邻两个数组元素的大小 } return ret; //返回最大值 } int main() { int array[5] = {1,2,3,4,5}; //定义整型数组 int iret = Max<int,5>(array); //调用函数模板 Max(),数组类型为 int,数组元素个数为 5 cout << iret << endl; double dset[3] = {10.5,11.2,9.8}; //定义浮点型数组 double dret = Max<double,3>(dset); //调用函数模板 Max(),数组类型为 double,数组元素个数为 3 cout << dret << endl; }程序运行结果为:
5
11.2
模板只作用于其下方的类或函数,所以在类外实现成员函数时要在函数前进行模板声明(即使函数没有用到该模板类型,类名里也要加上 <Type>)。
C++重载函数模板
编译器可以直接比较整型、浮点型和字符型数据,所以使用函数模板后也可以直接对这 3 种类型进行比较。但要比较字符指针指向的字符串,则需要通过重载函数模板实现(具体比较可使用库函数 strcmp())。【实例】寻找最小值。先定义一个函数模板,功能是寻找两个数中的最小值;再重载该函数模板,寻找字符串中的最小值;最后在主函数中调用函数模板。具体代码如下:
#include <iostream> #include <string> using namespace std; template <class Type> //模板头,Type 表示待比较两个数的数据类型 Type mymin(Type a,Type b) //定义函数模板 mymin(),求解两个数中的最小值 { if(a < b) return a; else return b; } char *mymin(char *a,char *b) //重载函数模板 mymin(),求解两个字符串中的最小值 { if(strcmp(a,b)) return b; else return a; } int main() { cout << "最小值:" << mymin(10,1) << endl; cout << "最小值:" << mymin("a","b") << endl; cout << "最小值:" << mymin("hi","mr") << endl; }程序运行结果为:
最小值:1
最小值:a
最小值:mr
min() 是系统函数,用户定义的函数名不能与系统函数名相同,所以这里定义为 mymin()。