摘要: 本篇博客仅作为笔记,如有侵权,请联系,立即删除(网上找博客学习,然后手记笔记,因纸质笔记不便保存,所以保存到网络笔记)。
在大多数情况下我们容易确定某次调用应该选择哪个重载函数,然而,当几个重载函数的形参数量相等以及某些可以由其他类型转换而来时,这项工作就不那么容易了。
void f(); void f(int); void f(int,int); void f(double,double = 3.14); f(5,6) //调用void f(double,double)
一、确定候选函数和可行函数
函数匹配的第一步是选择本次调用对应的重载函数集,集合中的函数成为候选函数。
候选函数特征:
1、与被调函数的函数同名
2、其声明在调用点可见
在上面的例子中,有4个名为f的候选函数。第二步考察本次调用提供的实参,然后从候选函数中选出能被这组实参调用的函数,这些新选出的函数成为可行函数,可行函数特征:
1、形参数量与本次调用提供的实参数量相等,而是每个实参的类型与对应的形参类型相同,或者能够转化为形参的类型。
2、每个实参的类型与对应的形参类型相同,或者可以转换成形参的类型。
我们能根据实参的数量从候选函数中排除掉两个,无参数和两个int类型参数都不行,而一个int和默认值的两个double类型都是可行的。
二、寻找最佳匹配
函数匹配的第三步是从可行函数中选择与本次调用最匹配的函数。在这一过程中,逐一检查函数调用提供的实参。
如果有多个可行函数,那么编译器依次检查每个实参以确定哪个函数是最佳匹配。如果有且只有一个函数满足下列条件,则匹配成功:
· 该函数每个实参的匹配都不劣于其他可行函数需要的匹配
· 至少有一个实参的匹配优于其他可行函数提供的匹配
若无函数脱颖而出,编译器会报错,认为此为二义性调用。
三、实参类型转换
1、精确匹配,包括以下情况:
· 实参类型和形参类型相同
· 实参从数组类型或函数类型转换成对应的指针类型
· 向实参添加顶层const或者从实参中删除顶层const
2、通过const转换成实现的匹配
如果重载函数的区别在于它们引用类型的形参是否引用了const,或者指针类型的形参是否指向const,则当调用发生时编译器通过实参是否为常量来决定哪个函数
Record lookup(Account &); Record lookup(const Account&); const Account a; Account b; lookup(a);//调用Record lookup(const Account &); lookup(b);//调用Record lookup(Account &);
在第一个调用中,我们传入的是const对象。因为普通引用不可以绑定到const对象中所以唯一可行的函数就是以常量引用作为形参的那个函数;
在第二个调用中,两个函数都是可行的,但是非常亮对象b初始化常量引用需要进行类型转换,接受非常量形参的版本则与b精确匹配。
3、通过类型提升和算术类型转化实现的匹配
一般小整型一般都会提升到int类型或者更大的整数类型。假设有两个函数,一个接收int,一个接收short,则只有当调用提供的是short类型的值才会选择short版本的函数,有时候,即使实参是很小的整数值,也会直接将它提升为int类型;此时使用short版本反而会导致类型转换:
void ff(int); void ff(short); ff('a'); //char提升成int,调用ff(int)
注意:所有算术类型转化的级别都一样,例如int向usigned int的转换并不比int向double的转换级别高:
void mainip(long); void mainip(float); mainip(3.14); //二义性调用
3.14的类型是double,所以既可以转换成long也可以转化成float,因为存在两种可能的算术类型转换,因此该调用具有二义性
4、函数指针
函数指针指向的是函数而非对象。和函数的类型由它的返回类型和形参类型共同决定,与函数名无关。
bool lengthCompare(const string &,const string &);
该函数想要声明一个可以指向该函数的指针,只需要用指针替换函数名即可:
bool (*pf)(const string &,const string &);
pf两端的括号必不可少,如果不写这对括号,则pf是一个返回值为bool的指针的函数