1)、函数重载的介绍
所谓的函数重载,其实就是同名的函数,具有不同的参数列表【但它们必须在同一作用域之内,不然就算不上函数重载,因为内层同名函数会隐藏掉外层同名函数】。为什么需要函数重载呢?考虑这样一种情况,比如我们要写一个函数max,我们传递给它两个参数,它返回一个更大值,类似这种【int max(int a, int b){ ...... }】,但这个函数只能处理int值,如果要处理char值,我们也可以写个同名的函数max,但参数列表必须不一样【char max(char a, char b){ ...... }】,下面是代码示例:
#include <iostream>
using namespace std;
int max(int a, int b) //函数1
{
cout << "我们调用的整型函数,返回的值是:";
return a > b ? a : b;
}
char max(char a, char b) //函数2
{
cout << "我们调用的字符型函数,返回值是:";
return a > b ? a : b;
}
int main()
{
cout << max(50, 99) << endl; //调用第1个函数
cout << max('2', 'B') << endl; //调用第2个函数
system("pause");
return 0;
}
既然函数名字都是相同的,那么编译器如何区分这些函数呢?虽然对于我们纯人用户来说,名字看起来貌似相同,但对编译器来说,是很容易区分的:编译器封装了一些黑魔法,使得这些“同名函数”并不相同,以上面的max函数为例,第一个max的在编译器里面的符号表很可能表示为【max_int_int(int a, int b)】,而第二个max的符号表则可能是【max_char_char( char a,char b)】,这样做的道理不难理解:既然同名函数的参数列表不同,那么为什么不能把参数列表作为函数名称的一部分呢,这样编译器不就能够处理同名矛盾了吗,反正我们的目的是尽可能的给用户方便,让编译器辛苦一点,谁会在乎呢。。。
接下来谈一下重载函数的匹配,以下内容借鉴自词条
/*******************************************************************************
1、精确匹配:函数的参数几乎不作任何处理,最多做一些很微小的“转换”【如数组名转换为指针,或函数名转换为指向函数的指针,或const int转换为int等】
2、提升匹配:比如char类型提升为int型,float型提升为double型
3、使用标准转换匹配:如int到double,float到int,char到int等
4、使用用户自定义匹配
5、使用省略号匹配:类似printf中的变长参数表
编译器的第一步,是确定该调用中所有的重载函数的集合,这个集合被称为候选函数(candidant function);然后第二部分为两个动作,第一个动作是编译器从候选函数中选出可行函数(viable function),可行函数的参数个数要么与实际的被调用函数相等,要么比调用函数多【但是多出来的函数参数都要有缺省值】,然后第二个动作是根据参数类型的转换规则将被调用函数的实参转换为候选函数的参数;最后一步是根据第二步筛选出的候选函数中选出最佳匹配函数。
3)、重载函数的注意事项
首先是关于引用,比如【int max( int a, int b)】和【int max(int &a, int &b)】,表面上看,它们的参数列表不一样,但实际上,编译器没法区分它们,在实际的调用中,也没法区分应该调用哪个函数,因为它把类型引用和类型本身视为同样的特征,如果我们非要这样做,那么只能如下所示报错:
其次,编译器也不区分const和非const的区别,就像下面的图片所示:
最后要说明的是,函数重载依靠的是参数列表,而不是返回类型!像下面的代码示例,就无法通过编译: