C++ 函数匹配
确定候选函数和可行函数
函数匹配的第一步是选定本次调用函数的重载函数集,集合中的函数称为候选函数,候选函数具有两个特征
1是与被调用函数同名
2是其声明在调用点可见
第二步考察本次调用提供的实参,然后从候选函数中选出能被这组实参调用的函数,这些新选出的函数称为可行函数,可行函数也有两个特征
1是其形参数量与本次调用提供的实参数量相等
2是每个实参的类型与对应的形参类型相同或者能够转换。
我们可以根据实参的数量从候选函数中排除两个(第一个和第三个),其中第四个函数本应该接受两个double值,但是因为它含有一个默认实参,所以只用一个实参也能调用。上述调用中第二个函数也是可行的,因为5.6可以转换为int型,但是第四个函数恰好匹配到了double型,与函数使用的完全一致。
注意:就像第四个函数,我们输入的实参可能少于我们实际调用函数的形参。一旦我们一个函数也无法匹配,那么编译器就会报错。
寻找最佳匹配(如果有的话)
函数匹配的第三步是从可行函数中选择与本次调用最匹配的函数,这一过程中,逐一检查函数调用提供的实参,寻找形参类型和实参类型最匹配的可行函数,他的基本思想就是实参类型和形参类型越接近匹配的越好。
在我们的例子中,调用只提供了一个显式的实参,是double类型,如果调用f(int),实参将不得不从double转换为int,另一个函数恰好是double,可以和实参精确匹配,因此调用第四个函数,编译器会为我们自动补上第二个实参。
含有多个形参的匹配函数
当实参的数量有两个或者更多时,函数匹配就比较复杂了,试想如果我们调用
会发生什么
首先编译器会选择那些形参数量满足要求且实参类型和形参类型能够匹配的函数。同样时第二个和第四个函数,接下来编译器依次检查每个实参以确定那个函数时最佳匹配,如果有且只有一个函数满足
1该函数每个实参的匹配都不劣于其他可行函数
2至少有一个实参的匹配优于其他可行函数
如果在检查了所有实参之后没有任何一个函数脱颖而出,则函数调用是错误的,编译器将报告二义性调用的信息。
那么对于上面的调用第一个实参用f(int,int)更好,但是第二个实参用f(double,double)更好,编译器最终将因这个调用具有二义性而拒绝其请求。
实参类型转换
为了确定最佳匹配,编译器将实参类型到形参类型的转换分成了几个等级。
1精确匹配(包括实参类型和形参类型相同;实参从数组类型或函数类型转换成对应的指针类型;向实参添加顶层const或者从实参中删除顶层const)
2通过const转换实现匹配
3通过类型提升实现的匹配
4通过算术类型转换或指针转换实现的匹配
5通过类类型转换实现的匹配
上面有些我们以后会介绍
需要类型提升和算术类型转换的匹配
注意:内置类型的提升和转换可能在函数匹配是产生意想不到的后果,但幸运的是,在设计良好的系统中函数很少会喊由于下面例子类似的形参
只有当调用提供的时short类型才会选择short版本,有时候即使实参是一个很小的整数,也会直接将他提升为int型,此时short版本反而会导致类型转换。
所有算术类型转换级别一样高,例如int向unsigned int转换并不从int向double转换级别高
字面值3.14的类型时double,它既能转换为long也能转换为float,因为存在两种可能的转换所以该调用具有二义性。
函数匹配和const匹配
如果重载函数的区别在于他们的引用类型的参数是否引用了const或者指针类型的形参是否指向了const,则当调用发生时编译器通过实参是否为常量来决定调用的函数
在第一个调用中,我们传入的是const对象b,因为不能把普通引用绑定到const对象上,所以此例中为一个可行函数是以常量引用作为形参的那个函数,并调用该函数与b精确匹配。
第二个调用中,我们传入的是非常量对象c,这个调用两个函数都可行,然而c的精确匹配是非常量引用,所以选择非常量版本。
指针类型的形参也类似,如果两个函数唯一的区别是他的指针形参指向常量或者非常量,则编译器通过实参能否是常量决定使用哪个函数。

