函数重载可以让您使用多个同名函数,这有那些有点呢,比如我写一个加法的函数
int add(int a.int b) {return a+b;}
要是我们现在需要一个三个数的加法呢
int add(int a.int b, int c) {return a+b+c;}
这在C语言中是行不通的,因为函数重名了,但是在C++中都是可以的,因为这属于函数多态,一个加法函数就可以实现两个,三个,四个。。。数的加法,也可以实现浮点数或者整数的加法。
函数重载的关键是函数的参数列表,也叫函数的特征标(function signature),如果两个函数的参数数目和类型相同,同时参数的排列顺序也相同,则他们的特征标相同,编译器认为是一个函数。
int add(int a, int b) {
std::cout << "add1" << std::endl;
return a + b;
}
double add(double a, double b) {
std::cout << "add1" << std::endl;
return a + b;
}
int main() {
std::cout << add(3, 3) << std::endl;
std::cout << add(3.14, 3.14) << std::endl;
}
# include "iostream"
int add(int a, int b) {
std::cout << "add1" << std::endl;
return a + b;
}
int add(int a, int b, int c) {
std::cout << "add2" << std::endl;
return a + b + c;
}
int main() {
std::cout << add(3, 3) << std::endl;
std::cout << add(3, 3, 4) << std::endl;
}
# include "iostream"
int add(int a, double b) {
std::cout << "add1" << std::endl;
return a + int(b);
}
int add(double a, int b) {
std::cout << "add2" << std::endl;
return int(a) + b;
}
int main() {
std::cout << add(3, 3.14) << std::endl;
std::cout << add(3.15, 3) << std::endl;
}
这个函数的输出是这样的
add1
6
add2
6
但是,但是,但是如果我们注释掉一个add函数,她的输出就是这样的
add1
6
add1
6
所以说明了什么,说明了编译器很智能,是的,很智能,参数只是顺序不同的话,有那个确定顺序的重载会去找那个确定顺序的重载,没有的话也可以找到一个参数类型相同的。
我们发现下面这个函数是无法被编译的
# include "iostream"
int add(int a, int b) {
std::cout << "add1" << std::endl;
return a + int(b);
}
int add(int &a, int &b) {
std::cout << "add2" << std::endl;
return a + b;
}
int main() {
int a = 1;
std::cout << add(a, a) << std::endl;
}
一个函数add的参数是两个整型,另一个函数的参数是两个整型的引用,但是会报错
error: call of overloaded 'add(int&, int&)' is ambiguous
说这个调用时模糊的,模棱两可的,为什么呢,主要的原因是因为在编译器看来,一个整数的引用和一个整数是等价的,所以编译器并不知道这里要调用哪个函数,所以类型引用和类型是一个特征标
和上面的引用一样,下面的程序也无法被编译
# include "iostream"
int add(int a, int b) {
std::cout << "add1" << std::endl;
return a + int(b);
}
int add(const int a, const int b) {
std::cout << "add2" << std::endl;
return a + b;
}
int main() {
int a = 1;
std::cout << add(a, a) << std::endl;
}
因为两个add函数被视为一个,相当于函数被重新定义了,这是cpp不允许的,但是const指针和普通的指针的特征标不一样,
# include "iostream"
int add(int* a, int* b) {
std::cout << "add1" << std::endl;
return *a + *b;
}
int add(const int* a, const int* b) {
std::cout << "add2" << std::endl;
return *a + *b;
}
int main() {
int a = 1;
std::cout << add(&a, &a) << std::endl;
}
上面这段程序可以被正常执行就是因为普通的指针可以赋值给普通指针也可以被赋值为const指针,但是const指针只能被赋值给const指针,这么说可能有点绕,那上面的程序做个例子,上面的程序其实是可以执行add1和add2的,都是合法的,但是如果我们传入的是一个const指针的话,只能执行add2了
重载函数很好用,但是不应该被滥用,只有当函数执行相同的任务但是参数不同时才应该被使用。而且不仅重载,使用默认参数也可以达到一定的重载功能。
C++如何跟踪一个重载参数呢,他给了这些函数不同的函数名,也就是编译器执行的名称修饰或者叫名称矫正,他根据每个函数中的形参列表对函数名进行加密处理,比如下面这个未处理的函数原型
long MyFunctionFoo(int,float);
这种格式对于人很友好但是对于编译器并不友好,所以会被修饰
?MyFunctionFoo@@YAXH
对原始名称进行的表面看来无意义的修饰(或矫正,因人而异)将对参数数目和类型进行编码;添加的一组符号随函数特征标而异,而修饰时使用的约定随编译器而异。
名称修饰后的函数名其实已经对不同函数重载已经有了不同的函数名。