一、函数的重载
函数的重载是一个非常常见的技术应用,可以这么说,开发者即使没有写过重载的代码,但一定用重载的代码。况且只要正规学习过书本的,在学习时都会有重载机制的相关知识点。重载看上去非常简单,但实际上,在应用时会有很多的技术小陷阱,搞不好就掉了下去。轻则达不到开发的目的,重则可能引起崩溃的情况。
二、函数重载的问题
下面看一个函数重载的异常的代码:
#include <iostream>
void print(int x) { std::cout << x << std::endl; }
template <typename T> void print(T &&x) {
print(x); // 无限递归
}
int main() {
print(100);
return 0;
}
上面的代码会导致栈溢出,从而引发程序的崩溃。主要原因在于100是一个右值,它会匹配print(T &&x)的右值引用,进而不断匹配此模板函数,导致无限递归,把栈耗尽,最终崩溃。其实还有很多类似的问题,在重载中需要开发者进行控制,否则极可能复现上述代码的结果。
函数重载的确定需要保证以下几个原则在确定优先级:
- 精确匹配(Exact Match)
这个最好理解,完全保持一致的对应,属于最基础的应用方式 - 提升转换(Promotion,如 char=>int)
如果重载中没有完全一致的,编译器则会进行一系列的转换,从而匹配相关函数。提升在转换中是一种相对安全一些的转换。不过,危险就是从此开始的。 - 标准转换(Standard Conversion,如 int =>double)
这个如同上面的2一样,强制转换,会更危险一些 - 用户定义转换(User-defined Conversion)
这个也比较好理解,比如用户自定义一个类默认值为int,则就形成了自定义转换 - 可变参数匹配(…)
这个是相对来说比较复杂的,在所有的上述匹配都无效的情况下,才会使用这种。
一般来说,函数重载需要对函数的签名进行如下的处理,来最终确定到底使用哪个函数:
- 重载函数查找
在整个编译单元中找出所有同名的函数,它包括限定查找和非限定查找,以及前面分析过的ADL查找,还有一个,就是友元函数的处理 - 构建相关的重载函数集
编译器依据函数名、参数数量及类型匹配度,从当前作用域内查找出可能调用的相关目标函数 。此处要特别注意函数模板以及类模板实例化的影响。在正常情况下,普通函数的匹配优先于模板函数 - 可行函数分析
对得到的重载函数集进行具体的分析,包括参数数量,参数类型等 - 最优匹配
根据相关规则选取最优的函数进行调用
三、函数重载问题常见种类
函数重载在C++中是一个非常被忽视的技术细节,出现问题的情况也有很多种,主要包括:
- 数据类型转换的问题
- 模板与普通函数的匹配问题
- 运算符重载的问题
- 限定符和修饰符的重载问题
- 移动主义重载问题
- 模板特化与重载问题
- 默认参数的重载问题
上面的这些问题,会在后面的文章中逐一进行分析说明。
四、总结
本文算是对函数重载问题的一个整体的概述,在后面会对其各种具体的问题进行一一的分析说明。让开发者可以将其中的一些技术细节掌握的清楚,从而在处理类似问题时有据可依,也能够快速的解决在实际工程中发现的相关问题。


被折叠的 条评论
为什么被折叠?



