1. 函数重载的概念
函数重载是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 顺序)必须不同,常用来处理实现功能类似数据类型不同的问题。
如:
void add(int a, int b);
void add(int a, int b,int c);
void add(int a, float b);
》
void add(float b,int a);
以上的几个函数都互相构成重载函数,但是有一点要注意的,函数返回值的是不同是不能构成重载函数的。
1.2 为什么需要函数重载
1_ 假设在C中,要想通过调用ADD函数来处理数据,由于数据类型不同,就需要为不同的函数进行修饰,即ADD_id,ADD_ii等等,无论是在调用或者是实现都显得极为麻烦;
2_ 操作符重载的本质也是函数重载;
2. 重载函数的调用匹配机制
精确匹配: 参数匹配,不进行转换;
提升匹配: 参数进行整形提升,如:int–>long,short–>int;
使用标准转换匹配: 将参数进行转换后匹配,如:int–>double,double–>int;
无参数匹配;
如果有多个重载函数被找到,那么调用会被拒绝,例:
void x(long);
void x(char);
void k(int i)
{
x(i);//调用x(long)?还是x(char)?
}
int main()
{
k();
return 0;
}
又或者是
int add(int a, int b)
{
return a + b;
}
int add(double a, double b)
{
return a + b;
}
int k(int a, double b)
{
add(a, b); //调用add(int,int)?或者是add(double,double)
}
int main()
{
k(10,10.0);
return 0;
}
多个重载函数可能会产生歧义或者是模棱两可的现象都会导致编译器报错
3.名字修饰
为什么C语言不支持重载函数,而C++支持重载函数呢,在C/C++中,一个程序要运行起来,需要经历以下几个阶段:预处理、编译、汇编,链接。
预处理阶段对源代码进行是文本操作,然后将.c文件变成.i文件
1:展开头文件
将include包含的头文件进行替换,替换成头文件的内容
2:删除注释
认为写的注释只是为了我们更好的理解代码,而计算机不需要
3:#define定义符号的替换
编译:
在编译阶段会将c语言代码转换为汇编代码,然后进行语法分析,词法分析,语义分析,符号汇总,编译器在检测语法错误的时候就是在这个阶段进行。
汇编:
将编译阶段生成的汇编代码转换成二进制文件,生成CPU理解的指令级代码,并且生成符号表。
其中,符号表是用来存放函数地址和函数名的,实际我们的项目通常是由多个头文件和多个源文件构成,不同文件都会生成各自的符号表。
链接
在编译后,a.o的目标文件中没有Add的函数地址,因为Add是在b.cpp中定义的,所以Add的地址在b.o中。链接器看到a.o调用Add,但是没有Add的地址,就会到b.o的符号表中找Add的地址,然后链接到一起。
那么C++是怎么解决名字冲突的问题呢?
在C语言中,是直接以函数名字作为符号表中的名字,所以C语言在形成符号表后,在链接过程中如果出现两个相同的函数名时,会出现错误,而C++为了解决这个问题,就将函数名根据参数来进行修饰,所以能在链接过程中找到对应的函数地址。
不同的编译器函数名字修饰不同,比如在Linux下,函数修饰为_Z+函数长度+函数名+类
型首字母。
通过这里就理解了C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修饰规则来区
分,只要参数不同,修饰出来的名字就不一样,所以支持重载。