一、函数匹配
在大多数情况下,比较容易确定某次调用应选用哪个重载函数,然而当几个重载函数的形参数量相等以及某些形参的类型可以由其他类型转换得到时,这个相对就不那么容易。
1.1 实参类型转换
确定最佳匹配,编译器将实参类型到形参类型的转换分成以下几个等级:
1.精确匹配,包括:
①实参类型和形参类型相同;
②实参从数组或函数类型转换成对应的指针类型;
③向实参添加层const或者从实参中删除顶层const。
2.通过const转换实现的匹配。
3.通过类型提升实现的匹配。
4.通过算术类型转换或者指针转换。
5.通过类类型转换实现的匹配。
①需要类型提升和算术类型转换的匹配。分析函数调用前,我们应该知道小证书一般都会提升到int类型或更大的整数类型。假设两个函数,一个接受int、另一个接受short,则只有当调用提供的是short类型的值时才会选择short版本的函数。有时即使实参是一个很小的整数值,也会直接将它提升成int类型,此时使用short版本反而会导致类型转换:
void ff(int);
void ff(short);
ff('a'); //char提升成int,调用ff(int)
所有算术类型转换的级别都一样,例如从int向unsigned int的转换并不比从int向double的转换级别高。
void mainp(long);
void mainp(float);
mainp(3.14); //错误,二义性调用
1.2 函数匹配和const实参
如果重载函数的区别在于它们的引用类型的形参是否引用了const,或者指针类型的形参是都指向const,则当调用发生时编译器通过实参是否是常量来决定选择哪个函数。
Record lookup(Account&); //函数的参数是Account的引用
Record lookup(const Account&); //函数的参数是一个常量引用
const Account a;
Account b;
lookup(a); //调用lookup(const Account&)
lookup(b); //调用loopup(Account&)
二、函数指针
函数指针指向的是函数而非对象,函数的类型由它的返回类型和形参类型共同决定,与函数名无关.
bool lengthCompare(const string &,const string &);
上述函数的类型是bool(const string & ,const string & ),要声明一个可以指向该函数的指针,只需要用指针替换函数名即可。
//pf指向一个函数,该函数的参数是两个const string的引用,返回值是bool类型
bool (*pf)(const string &, const string &); //未初始化
pf前面有个表示pf是指针,右侧是形参列表,表示pf指向的是函数,函数的返回类型是布尔值,所以pf是一个指向函数的指针,该函数的参数是两个const string的引用,返回值是bool类型。需要注意的是*pf两端的括号不可少,如果不写这对括号,那么表示pf是一个返回值为bool指针的函数,即函数返回bool。
2.1 使用函数指针
如果把函数名作为一个值使用,该函数自动地转换成指针。如下间lengthCompare的地址赋给pf。
pf = lengthCompare; //pf指向名为lengthCompare的函数
pf = &lenghtCompare; //等价的赋值语句,取址符是可选的
bool b1 = pf("hello","goodbye"); //调用lengthCompare函数
bool b2 = (*pf)("hello","goodbye"); //一个等价的调用
bool b3 = lengthCompare("hello","goodbye"); //另一个等价的调用
2.2 重载函数的指针
当我们使用重载函数时,上下文必须清晰地界定到底应该选用哪个函数,如果定义指向重载函数的指针,编译器通过指针类型决定选用哪个函数,指针类型必须与重载函数中的某一个精确匹配:
void ff(int*);
void ff(unsigned int);
void (*pf1)(unsigned int) = ff; //pf1指向ff(unsigned)
void (*pf2)(int) = ff; //错误,没有任何一个ff与该形参列表匹配
double (*pf3)(int*) = ff; //错误:ff和pf3的返回类型不匹配
2.3 函数指针形参
和数组类似,虽然不能定义函数类型的形参,但是形参可以是指向函数的指针,这样形参看起来是函数类型,实际是当成指针来使用:
//第三个形参是函数类型,它会自动地转换成指向函数的指针
void useBigger(const string &s1,const string &s2,bool pf(const string &,const string &));
//等价的声明,显式地将形参定义成指向函数的指针
void useBigger(const string &s1,const string &s2,bool (*pf)(const string &,const string &));
2.4 返回指向函数的指针
和数组类似,虽然不能返回一个函数,但是能返回指向函数类型的指针,此外,必须把返回类型写成指针形式,编译器不会自动地将函数返回类型当成对应的指针类型处理。声明一个返回函数指针的函数,最简单的办法是使用类型别名:
using F = int(int*,int); //F是函数类型,不是指针
using PF = int(*)(int*,int); //PF是指针类型
PF f1(int); //正确,PF是指向函数的指针,f1返回指向函数的指针
F f1(int); //错误,F是函数类型,f1不能返回一个函数
F *f1(int); //正确,显式地指定返回类型是指向函数的指针
int (*f1(int))(int*,int); //正确,直接声明f1
参考文献:
①C++ primer 第五版