这是我参与11月更文挑战的第9天,活动详情查看:2021最后一次更文挑战
函数重载
对于函数而言,不同的参数列表的同名函数即为重载行为:
void print(const char * str, int width); // #1
void print(double d, int width); // #2
void print(long l, int width); // #3
void print(int i, int width); // #4
void print(const char *str); // #5
print("Pancakes", 15); // 调用 #1
print("Syrup"); // 调用 #5
print(1999.0, 10); // 调用 #2
print(1999, 12); // 调用 #4
print(1999L, 15); // 调用 #3
注意函数重载的实现是依靠声明不同的参数列表,而非返回类型,函数重载的底层实现是由于编译器的如下操作:
long MyFunctionFoo(int, float); \\你的函数声明
?MyFunctionFoo@@YAXH \\ 编译器干的
根据函数返回值、函数名、参数列表,编译器会进行一个称为name decoration 或name mangling的操作,生成一段hash一样的函数标识符(因而函数参数列表也被称为函数签名)。
函数模板
先来看看函数模板是怎么使用的。
template <typename T>
void Swap(T &a, T &b);
int main(){
using namespace std;
int i = 1;
int j = 2;
Swap(i,j);
std::cout << i << ',' << j;
double x = 1.0;
double y = 2.0;
Swap(x,y);
std::cout << x << ',' << y;
}
template <typename T>
void Swap(T &a, T &b){
T temp;
temp = a;
a = b;
b = temp;
}
函数模板和函数重载都使编码更高效,一个避免了因为类型不同反复实现同样的逻辑,一个提供了更好的语义性。
编译器如何处理重载函数与函数模板
由于多个重载的函数、以及函数模板(甚至函数模板的重载)的存在,当一个函数被调用时,可能能够精确定位到某一个函数声明(Exact Match),但也可能出现能够定位到多个函数声明的情况,这时编译器会根据一些原则进行trivial conversion,找到一个最合适的函数,如果失败了,就报错,关于这种转换的优先度规则,就跟css优先级这种东西一样,死记没必要,用起来自然就懂了,这里甩个查阅的链接。