在c++ 中,众所周知,为了和c语言向下兼容,c++做出了很多的牺牲和让步,在这里面,函数,比c语言中的函数更要复杂和麻烦。
c语言中的函数是不具有重载的,所以函数名即名字,在编译链接时,若是两个文件中有重复的名字最多报一个错误而已,而c++中,却多出了不少问题:
普通函数重载
首先,拥有的函数重载,重载的名称问题。
拥有了一些东西,你也失去了一些东西。
int foo() {}
int foo(int x) {}
int main() {
std::function<int(int)> f = foo;
return 0;
}
试试看上述代码是否可以编译通过,若是不行,如何改正?
重载给我们带来了一种假象,让我们可以传不同的参数进去然后转发到不同的函数去执行。
看着很美好,其实并不是那么的美妙。
先看看c++的重载是如何做的吧!
现在我们有一个不重载的函数:
用nm
来看看其名字是如何的:
现在,nm
告诉我们,这个函数的名字叫做 _Z4testv
多写几个函数试试:
用nm
看看结果
发现,名称其实还是有一些规律,
以_Z4
为前缀,参数名其后依次排序(g++里面int参数名是i,double是d)
可以使用c++filt
来进行解析名称
那么,我们可以就直接用这个名称进行调用吗?
讲道理,在汇编层面,我觉得是可以的,来试试看
先看看汇编上的名字是不是刚才那样的名字
c++也遵循c语言的abi
,所以,按理来说,c语言可以直接链接c++编译出来的二进制文件
现在我们的c语言调用代码如下:
可以发现,我们只是简单的声明了一下即可,为了链接地址所用
现在将 c文件编译,然后和c++的这个demo
文件进行链接
然后,我们就可以对这个名字直接进行调用
归根结底,其实我们发现,c++重载无非就是进行名称重写罢了,没什么稀奇的。
但是,有时候,重载却会给你带来一些坑
比如下列代码:
#include <stdio.h>
void fun(int) {
printf("fun int\n");
}
void test() {
fun('a');
}
void fun(char) {
printf("fun char\n");
}
int main() {
test();
return 0;
}
你觉得应该是输出什么呢?
反正在我的机器上输出的是 fun int
。
我机器是编译器是:gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.1)
成员函数or命名空间内函数重载
那么,上面说了普通函数的重载,成员函数重载又是什么样子呢?
用 nm
打印出来是这个样子的:
可以看到,这个名字为什么和普通重载的不一样呢?
那么,命名空间内的函数重载形式是什么样子呢?
_ZN4Demo3funEi
很好分析,意思是 4 Demo 3 fun
,前面的命名空间是Demo,然后是Demo下的fun函数
数字用于分割参数与函数名之间的区别
题外话
若是c语言要调用c++现有内容,如何做呢?
正规做法: 采用 extern "C"的表示来不让起进行 name mangling
不正经的做法:c语言用已有c++库如何做呢,此时c++并没有兼容c的想法,意思是c语言很尴尬的调用不到同名的函数,因为被重载掉了,找出 name mangling 后的函数名,手动构造所需参数进行调用(自己玩玩就好了,不能真的用在实际中)
[amjieker]