一、什么是函数重载?
二、为什么c不支持函数重载?
1.编译与链接
首先我们要找到,一个c/c++程序要运行起来,需要经过预处理、编译、汇编、链接四个阶段。下面我们先来回顾一下各个阶段编译器都做了什么事情。预处理:进行头文件的替换、宏的替换。编译:进行语法分析、词法分析、语义分析、符号汇总。汇编:生成二进制指令,生成符号表。链接:合并段表,进行符号表的合并和重定位。
我们假设两个文件分别是A.cpp和B.cpp,在B.cpp中,我进行了对函数ADD的定义。而在A.cpp中我调用了此ADD函数。由于每个文件的编译都是单独进行的,因此在链接前,编译器无法在A.cpp中找到ADD的地址,(因为ADD的定义在文件B.cpp中),所以在A.cpp中进行了对函数ADD的声明,相当于给了编译器一个承诺。而在链接过程中,将符号表合并后,链接器可通过符号表找到ADD的地址,相当于兑现了承诺。
2.函数名修饰规则
那么链接时,面对Add函数,链接接器会使用哪个名字去找呢?这里每个编译器都有自己的函数名修饰规则,由于Windows环境下的修饰规则较为复杂,所以这里用Linux环境进行演示。
采用c语言的编译器编译后结果:
我们可以看到,编译完成后,函数名字并没有被修改,而是直接使用了函数名。
采用c++的编译器编译后结果:
采用g++编译完成后,函数名字的修饰发生改变,编译器将函数参数类型信息添加到修改后的名字中。变成了[Z+函数长度+函数名+类型首字母],这样就使链接器能精准地找到需要的函数,而不是错误地找成了同名的函数。
这样我们就知道了c语言不支持函数重载的原因:因为c语言的编译器不会对函数名字进行修饰和改变,而是直接使用其函数名,这使得同名函数无法区分。而c++通过函数修饰来区分,只要函数参数不同,修饰出来的名字也就不同,从而便支持了重载。
同时,我们也能找到为什么函数返回值不同不能构成重载。若函数名和函数参数都相同,返回值不同,编译时修饰出来的名字是一样的,也就无法区分。