函数重载:使用相同的函数名定义多个函数,每个函数具有不同的参数列表
int fun(int val) { return val; }
double fun(int val) { return val; }
int main() { fun(1); }
这样写会进行报错,我们在15行进行函数调用时,没有使用返回值,这里就产生了歧义,返回值究竟是int类型还是double类型,从而引起报错。
- 函数重载与name mangling
** 名称查找 **
- 限定查找( qualified lookup )与非限定查找( unqualified lookup )
```cpp
#include <iostream>
void fun()
{
std::cout << "global fun is called" << std::endl;
}
namespace MySpace
{
void fun()
{
std::cout << "MySpace::fun is called" << std::endl;
}
}
int main()
{
::fun();
MySpace::fun(); // 指定了查找空间即MySpace中
}
void fun() { std::cout << “global fun is called” << std::endl; }
namespace MySpace { void fun() { std::cout << “MySpace::fun is called” << std::endl; } void g() { fun(); } }
int main() { MySpace::g(); }
输出结果:
```cpp
MySpace::fun is called
namespace MySpace { struct Str{}; void g(Str x) { std::cout << “successfully called” << std::endl; } }
int main() { MySpace::Str obj; g(obj); }
这里的obj作为实参,传入函数g( ),从而实现函数的成功调用
**_tricky point:_**
```cpp
#include <iostream>
template <typename T>
void fun(T x)
{
g(x);
}
namespace MySpace
{
struct Str{};
void g(Str x)
{
std::cout << "successfully called" << std::endl;
}
}
int main()
{
MySpace::Str obj;
fun(obj);
}
涉及到模板的一些问题时,看起来违背了“查找通常只会在已声明的名称集合中进行 ”,但这和编译器对模板的一些处理(如模板实例化)有关,其他情况依然适用
重载解析:在名称查找的基础上进一步选择合适的调用函数
– 过滤不能被调用的版本 (non-viable candidates)
● 参数个数不对
● 无法将实参转换为形参
● 实参不满足形参的限制条件
– 在剩余版本中查找与调用表达式最匹配的版本,匹配级别越低越好(有特殊规则)
● 级别 1 :完美匹配或平凡转换(比如加一个 const )
● 级别 2 : promotion 或 promotion 加平凡转换 (整型提升)
● 级别 3 :标准转换 或 标准转换加平凡转换
● 级别 4 :自定义转换 或 自定义转换 加平凡转换 或 自定义转换加标准转换
● 级别 5 :形参为省略号的版本
● 函数包含多个形参时,所选函数的所有形参的匹配级别都要优于或等于其它函数
situation 1
// lvalue i -> int& is better than lvalue int -> const int&
#include <iostream>
void fun(int& val)
{
std::cout << "The first fun is called!" << std::endl;
}
void fun(const int& val)
{
std::cout << "The second fun is called!" << std::endl;
}
int main()
{
int x;
fun(x);
}
编译结果:
The first fun is called!
很明显在函数重载中,主函数成功地调用了第一个fun( )函数,我们可以这样理解:x作为实参传入函数中,第一个左值引用绑定到x上,可以实现对x的读写操作,而第二个只能进行读取操作,编译器因此会选择第一个fun( )函数
situation 2
#include <iostream>
void fun(int val)
{
std::cout << "The first fun is called!" << std::endl;
}
void fun(const int& val)
{
std::cout << "The second fun is called!" << std::endl;
}
int main()
{
int x;
fun(x);
}
这段代码编译失败,根据上面的函数重载规则,第一步过滤没有问题,到第二步,根据匹配级别,两个函数同属于级别1,解析出现问题,因此会报错。
situation 3
#include <iostream>
void fun(int& val)
{
std::cout << "The first fun is called!" << std::endl;
}
void fun(const int& val)
{
std::cout << "The second fun is called!" << std::endl;
}
int main()
{
fun(3);
}
编译结果:
The second fun is called!
这里的3作为右值,而左值引用val不能绑定到右值上
situation 4
函数包含多个形参时,所选函数的所有形参的匹配级别都要优于或等于其它函数
// 错误代码
#include <iostream>
void fun(int val,double y) // 1 3
{
std::cout << "The first fun is called!" << std::endl;
}
void fun(int val,float y) // 1 3
{
std::cout << "The second fun is called!" << std::endl;
}
int main()
{
fun(1,1); // 重载解析出现歧义
}
tricky point:
#include <iostream>
void fun(bool val,float y) // 1 3
{
std::cout << "The first fun is called!" << std::endl;
}
void fun(int val,double y) // 2 1
{
std::cout << "The second fun is called!" << std::endl;
}
int main()
{
fun(true,1.0);
}
编译标准不同,在gcc下可以通过编译输出结果,在clang下直接报错,这里就涉及到比较“奇怪”的点 :按照匹配规则,多参数需要每个参数的级别都优于其他函数,此函数才可以作为函数重载解析的选择,但在gcc的标准下,给出了**warning: **ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second:
,可见这里它把级别之和作为选择标准,因此调用第二个fun( )函数:
The second fun is called!
更改:
#include <iostream>
void fun(bool val,float y) // 1 3
{
std::cout << "The first fun is called!" << std::endl;
}
void fun(int val,double y) // 1 1
{
std::cout << "The second fun is called!" << std::endl;
}
int main()
{
fun(static_cast<int> (true),1.0);
}
编译结果:
The second fun is called!