【写在前面】
自然语言中,一个词可以有多重含义,人们可以通过上下文来判断该词真实的含义,即该词被重载了。
比如:以前有一个笑话,国有两个体育项目大家根本不用看,也不用担心。一个是乒乓球,一个是男足。前者是 “谁也赢不了!”,后者是 “谁也赢不了!”
一、 函数重载概念
函数重载:是函数的一种特殊情况,C++ 允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表 (参数个数或类型或顺序) 必须不同,常用来处理实现功能类似数据类型不同的问题,显然这是 C 语言做不到的东西
//1.参数个数 int Add(int x) {} int Add(int x, int y) {} //2.参数类型 int Add(int x, int y) {} int Add(int x, double y) {} //3.参数顺序 int Add(int x, float y) {} int Add(float y, int x) {}
❗ 怎么调用 ❕
int Add(int left, int right) { return left + right; } double Add(double left, double right) { return left + right; } long Add(long left, long right) { return left + right; } int main() { //这里分别调用三种不同的函数 Add(10, 20);//默认整型 Add(10.0, 20.0);//浮点型 Add(10L, 20L);//长整型 return 0; }
⚠ 注意
对于函数重载,如果你想调用某一函数,那么在传参的时候就必须写好对应参数的类型、个数、顺序,比如 float 数据,就要写 3f,因为这样它才能找到对应的函数调用
二、 名字修饰 (name Mangling)
❓ 为什么C++支持函数重载,而C语言不支持函数重载呢,以 Linux 环境下演示 ❔
注意这里就不细讲 Linux 的一些指令了,具体的我都写在或者将写在 《Linux专栏》里了
先在 Linux 下以两种编译方式编译函数重载的程序,这里有三个文件 :f.h、f.c、test.c
▶ 可以看到以 C 语言去编译函数重载报错了
▶ 可以看到以 C++ 去编译函数重载是可以的
在正式探究前我们先回忆下,注意 C/C++ 都有类似的过程,但肯定是有区别的,现在我们要找的就是那个区别
这里我们对照着程序走一遍过程
然后再回到我们的问题
❓ C语言不支持函数重载 ❔
C 编译器,直接用函数名关联,函数名相同时,无法区分
❗ 验证 ❕
通过命令 objdump -S 去查看 C 编译生成的符号表
通过命令 objdump -S 去查看 C++ 编译生成的符号表
❓ C++ 支持函数重载 ❔
从上就可以看出对于函数重载 C++ 相对于 C 语言引入了某种规则
C++ 引用了《函数名修饰规则 (Linux下)》不能直接用函数名,要对函数名进行修饰 (带入参数的特点修饰)
📝 说明:
1️⃣ _Z 是前缀
2️⃣ 3 是函数名的长度
3️⃣ Add 是函数名
4️⃣ ii / dd 是函数参数类型的首字母,如果是 int* i,那么就是 pi
💨小结:
C++ 是支持函数重载的,函数名相同,只要参数不同,修饰在符号表中的名字也不同,那么就能区分了
❗ Windows下函数名修饰规则 ❕
🍳【扩展学习:C/C++函数调用约定和名字修饰规则】
❓ 下面两个函数属于函数重载吗 (编译器能不能只实现返回值不同,就能构成重载) ❔
short Add(short left, short right) { return left+right; } int Add(short left, short right) { return left+right; }
显然《函数名修饰规则》并不能让它们支持重载。
❓ 其次如果想自己定义《函数名修饰规则》让只有返回值不同的函数支持重载可以吗 ❔
💨 编译器层面是可以区分的
short Add; -> _Z3sAdd
int Add; -> _Z3iAdd
💨 语法调用层面有严重歧义
Add(3, 5); ???
❓ 下面两个函数能形成函数重载吗?❔
void TestFunc(int a = 10) { cout<<"void TestFunc(int)"<<endl; } void TestFunc(int a) { cout<<"void TestFunc(int)"<<endl; }
虽然两个函数的参数是缺省值和非缺省值,但是依旧不影响修饰出来的函数名,所以不能构成函数重载
三、 extern"C"
有时候在 C++ 工程中可能需要将某些 (部分) 函数按照 C 的风格来编译,在函数前加 extern “C”,意思是告诉编译器,将该函数按照 C 语言规则来编译。比如:tcmalloc 是 google 用 C++ 实现的一个项目,他提供 tcmallc() 和 tcfree两个接口来使用,但如果是 C 项目就没办法使用,那么他就使用 extern “C” 来解决。
extern "C" int Add(int left, int right); int main() { Add(1,2); return 0; }
💨总结
1️⃣ C++ 项目可以调用 C++ 库,也可以调用 C 的库,C++ 是直接兼容 C 的
2️⃣ C 项目可以调用 C 库,也可以使用 extern"C" 调用 C++ 库 (C++ 提供的函数加上 extern"C")