函数模板&泛型编程

当我们应用一个函数时,如果参数类型发生变化,那么原来的函数将不再适用,只有通过函数重载的方法重新实现一个适用于此参数类型的函数,如下所示。

int ADD (const int& _left , const int& _right)
{
    return(_left+_right);
}
char ADD(const char& _left , const char& _right)
{
    return(_left+_right);
}
int main()
{
    cout<<ADD(1,2)<<endl;
    cout<<ADD('A','1')<<endl;
}

运行结果如下:
这里写图片描述

但是通过函数重载实现所需函数有以下缺点:

  1. 只要有新类型出现就要重载一个新的函数。
  2. 这些函数除了类型外其余部分一样,代码复用率不高。
  3. 如果新的函数要求仅仅返回值不同,并没有满足函数重载的条件,函数重载不能提供这样的函数。
  4. 如果函数体出现错误,重载的函数也会出现错误,不好维护。

为了解决如上问题,引进泛型编程。泛型编程编写与类型无关的逻辑代码,是代码复用的一种手段,而其核心就是模板(包括函数模板和类模板,编译器可根据此模板合成所需函数或类)。
函数模板:代表了一个函数家族,该函数与类型无关,在使用时被参数化——产生所需的具体函数类型。模板函数具有以下格式

template<class/typename T>

T 函数名(T 参数1T 参数2...)
{
   函数功能
}

对于加法函数来说,其函数模板如下所示:

template<class T>

T ADD(T _left , T _right)
{
   return(_left+_right);
}

下面我们通过函数模板来实现不同类型参数的加法运算。

template<class T>
T ADD(T& _left , T& _right)
{
   return(_left+_right);
}
int main()
{
   cout<<ADD(1,2)<<endl;
   cout<<ADD('A','1')<<endl;
}

运行结果如下:
这里写图片描述

函数模板实例化

其实,在程序运行过程中,并不是直接通过函数模板得到运行结果,而是编译器将函数模板实例化——产生指定类型的函数,然后调用此函数得到结果。这个过程我们称为函数模板实例化,图解如下。

这里写图片描述

类型转换

函数模板的功能如此强大,那么编译器是否能通过函数模板实例化出任意类型的函数呢?答案是否定的。例如以下类型的函数,编译器并不能直接通过函数模板合成。

  cout << ADD('A',1) << endl;
  cout << ADD(1, 3.14) << endl;

原因是要求类型行参的实参必须完全匹配。

那么要通过函数模板实例化出上述类型的函数有什么方法呢?可以对函数实参进行类型转换(分为隐式和显式),如下所示。

//隐式类型转换
template<class T>
T ADD(const T& _left, const T& _right)
{
    return(_left + _right);
}

int main()
{
    cout << ADD((int)'A', 1) << endl;
    cout << ADD((double)1, 3.14) << endl;
    return 0;
}


//显式类型转换
template<class T>
T ADD(const T& _left, const T& _right)
{
    return(_left + _right);
}

int main()
{
    cout << ADD<int>('A', 1) << endl;
    cout << ADD<double>(1, 3.14) << endl;
    return 0;
}

运行结果如下:
这里写图片描述

注意:

  • 当函数实参类型为const引用(指针)类型时,编译器可以根据参数为非const引用(指针)的函数模板实例化出。
  • 编译器一般不会转换实参已匹配的实例化,会产生新的实例化。
  • 如果模板形参不是引用类型,则对数组或函数类型的实参应使用常规指针转换。数组实参将当做指向其第一个元素的指针,函数实参当做指向函数类型的指针,如下图所示:当使用引用类型做函数模板时会报错,而使用非引用类型时不会报错。

    这里写图片描述
    这里写图片描述

    非类型形参

    函数模板的另一种参数——非类型形参。
    若函数实参为数组或函数时,对应的函数模板应同时具有类型形参和非类型形参。

函数模板的重载

如下所示:

int MAX(const int&a,const int&b)
{
    return a > b ? a : b;
}
template<class T>
T MAX(const T &_left, const T& _right)
{
    return _left > _right ? _left : _right;
}
template<class T>
T MAX(const T& a,const T& b,const T& c)
{
    return MAX(MAX(a, b), c);
}
int main()
{
    MAX(10, 12);
    MAX(10, 12, 30);
    cout <<MAX(10,12) << endl;
    cout <<MAX<>(10,12) << endl;
    cout << MAX(10,12,30) << endl;
    return 0;
}

运行结果如下:
这里写图片描述
注意:

  • 如果一个普通函数和一个同名模板函数同时存在且其他条件都相同,则优先调用普通函数不会从该模板产生一个实例,但如果模板可以实例化出一个更加匹配的函数,那么将选择模板。
  • 模板函数不允许自动类型转换,但普通函数可以进行自动类型转换。
  • 显示指定一个空的模板实参列表,该语法告诉编译器只有模板才能匹配这个调用,而且该函数模板所有的模板参数都该根据实参演绎出来。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值