1,重载函数概述
出现在相同作用域中的两个函数,名字相同而形参表不同。
注意:
(1)重载函数必须位于相同的作用域,局部作用域中声明的函数 (谁会这么做?!)会屏蔽全局作用域中的重名函数;
(2)必须是形参表不同,而不能仅仅是返回类型不同。如果形参表完全相同,而返回类型不同,则第二个声明是错误的;
(3)可以基于成员函数是否为const而重载,const类只能调用const成员函数,非const类优先调用非const成员函数;
(3)形参表是否相同要看本质而不能只看形式,如下例:
// 1,参数名会被忽略,所以形参表相同
Record lookup(const Account &acct);
Record lookup(const Account&); // parameter names are ignored
// 2,编译时遇到Telno会被替换成Phone,导致两者形参表相同
typedef Phone Telno;
Record lookup(const Phone&);
Record lookup(const Telno&); // Telno and Phone are the same type
// 3,默认实参并不改变形参的个数,形参表相同
Record lookup(const Phone&, const Name&);
Record lookup(const Phone&, const Name& = "");
// 4,对于非引用或指针类型的形参,const限定符被忽略,形参表相同
Record lookup(Phone);
Record lookup(const Phone);
2,函数匹配
函数匹配,又名重载确定,是将函数调用与重载函数集合中的一个函数相关联的过程。2.1 函数匹配结果的3种结果
(1)编译器找到与实参最佳匹配(best match)的函数,OK;
(2)实参与重载函数集合中任何一个函数的形参都无法匹配,哪怕是在隐式类型转化之后,报错;
(3)存在多个与实参匹配的函数,但没有一个是明显的最佳选择,则此调用有二义性(ambiguous),报错;
2.2 函数匹配的步骤
(1) 候选函数
与被调用函数重名,且在调用点上其声明可见
(2)选择可行函数(viable function)
可行函数需要满足两点:
a. 形参个数与该调用的实参个数相同,但要注意默认实参的情况,默认实参也是实参;
b. 实参的类型必须与形参的类型匹配,或者可被隐式转化为对应形参的类型
关于类型匹配,分为两种情况:
a. 精确匹配
b. 实参类型经过隐式转换后匹配
(3)寻找最佳匹配(如果有的话)
原则:实参类型与形参类型越接近越好
(4)含有多个形参时的重载确认
如果有且仅有一个函数满足下列条件,则匹配成功
a. 每个实参的匹配都不劣于其他可行函数需要的匹配;
b. 至少有一个实参的匹配,优于其他可行函数提供的匹配;
如果找不到最佳匹配函数,则该调用有二义性错误
2.3 实参类型转换
确定最佳匹配所需的转换等级:
1. 精确匹配
2. 类型提升
3. 标准转换
4. 类类型转换
比如下面的代码:
void ff(int);
void ff(short);
ff('a'); // char promotes to int, so matches f(int)
实参'a'被提升为int型,与ff(int)匹配
关于整型提升,提一句:
/*******************************************************************/
// 整型提升
/*******************************************************************/
char a = 1;
char b = 2;
char c = 0;
c = a + b;
// 虽然类型相同,但是a和b都被提升为int型再进行加法运算
// 所以a+b占4个字节,
// 然后赋值给c,发生隐式类型转换,变为char型,只占1个字节
cout << "sizeof(c) = " << sizeof(c) << endl; // 1
cout << "sizeof(a+b) = " << sizeof(a + b) << endl; // 4
printf("c = %d\n",c);//c = 3
运行结果:
注意:没有哪个标准转换比其他标准转换具有更高的优先级
extern void manip(long);
extern void manip(float);
manip(3.14); // error: ambiguous call