函数重载
1. 函数重载的概念:
函数重载是函数的一种特殊情况,C++中允许同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数、类型、顺序)不同。
注意:顺序不同指的是不同类型的参数顺序不同,而不是单纯的同类型参数顺序不同
int Add(int left, int right)
int Add(int right, int left)
↑↑↑这样的不行↑↑↑
int Add(int left, long right)
int Add(long right, int left)
//只是随便举个例子,不要对这写的类型深究
↑↑↑这样的行↑↑↑
2. 名字修饰
两个常见问题:
什么是重载函数?
答:函数名相同,参数不同(个数、类型、顺序不同)
为什么C++支持函数重载,而C语言不支持
答:
首先,在C/C++中,一个程序要运行起来,需要经历以下几个阶段:预处理、编译、汇编、链接。
预处理:头文件展开/宏的替换/去注释/条件编译
编译过程:将高级语言转为汇编语言
1.项目通常是由多个头文件和多个源文件构成,而通过C语言的编译链接部分知道(当前a.cpp中调用了b.cpp中定义的Add函数时),编译后链接前,a.o的目标文件中没有Add的函数地址,因为Add是在b.cpp中定义的,所以Add的地址在b.o中。
2.所以链接阶段就是专门处理这种问题,链接器看到a.o调用Add,但是没有Add的地址,就会到b.o的符号表中找Add的地址,然后链接到一起。
3.那么链接时,面对Add函数,连接器会使用哪个名字去找呢?这里每个编译器都有自己的函数名修饰规则。
4.由于Windows下vs的修饰规则过于复杂,而Linux下gcc的修饰规则简单易懂,下面使用gcc演示了这个修饰后的名字。
通过下图可以看出gcc的函数修饰后名字不变,而g++的函数修饰变成(_Z+函数长度+函数名+类型首字母)
通过C语言编译器编译后的结果 如下图
结论:在Linux下,采用gcc编译完成后,函数名字的修饰没有发生改变
采用C++编译器编译后结果 如下图
结论:在linux下,采用g++编译完成后,函数名字的修饰发生改变,编译器将函数参数类型信息添加到修改后的名字中。
所以,C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载。(说白了就是C++链接时,是使用加参数修饰后的函数去查找,C语言链接时,时直接使用函数名去查找)
(同时也知道了为什么函数重载需要参数不同,而跟返回值无关)
3. extern"C"
3.1 extern"C"的定义
有时候C++工程中可能需要某些函数按照C的风格来编译,在函数前加extern"C",意思就是告诉编译器将该函数按照C语言规则来编译
比如 tcmalloc是Google用C++实现的一个项目,他提供tcmallc()和tcfree()两个接口来使用,但如果是C项目的话就没法使用,这样就可以用 extern"C"来解决这个问题