函数重载
什么是函数重载
简单来说 ,就是 可以有多个相同函数名的函数, 但是这些函数的参数个数 或者参数类型 或者参数的类型顺序 是不一样的.
通常来处理类似的功能,但是数据个数或者类型不同的情况
如:计算器就是一个例子 ,加法可以是任何个数任何类型的数的加法
但是都只按一个 " + "号就可以完成
如以下示例: 不同类型的加法
int add(int a, int b)
{
return a + b;
}
double add(double a, double b)
{
return a + b;
}
int add(int a, int b, int c)
{
return a + b + c;
}
//下面两个 不同类型的参数的顺序不同
double add(int a, double b)
{
return a + b;
}
double add(double a, int b)
{
return a + b;
}
int main3()
{
cout << add(1, 1) << endl;
cout << add(1.5, 2.3) << endl;
cout << add(1, 2, 3) << endl;
cout << add(1, 1.1) << endl;
cout << add(1.1, 1) << endl;
return 0;
}
注意
返回值不同 是不构成重载的,因为调用的时候,无法直接判断出调用谁
举个例子
short add(short a, short b)
{
return a+b;
}
int add(short a,short b)
{
return a+b;
}
int main()
{
add(1,2);//那么此时是调用哪一个呢? 无法区分!
return 0;
}
函数重载的意义就在于:让用的地方很方便,就像用同一个函数一样.
为什么C++支持函数重载,而C语言不支持?(Linux环境探究)
既然函数重载这么好用,那么函数重载的底层原理是什么呢?
C和C++程序运行起来需要经历 : 预处理、编译、汇编、链接
-
在汇编之后生成目标文件(Linux下.o)(windows下 .obj),之后就把所有的.o文件合并到一起. 并且main.cpp 里有一些头文件包含了 函数的声明或者变量的声明
-
此时这些头文件里的变量或者函数实际上是在其他的文件中定义的 , 而在main文件中需要调用 ,而函数的地址其实是函数中第一条指令的地址,它在定义函数的.o文件中, 所以就会去其他的.o文件中 去找这些只有声明的变量或者函数的地址 ,找到之后就可以调用了(编译成功) , 如果找不到 ,就会出现链接错误(LINK ERROR)。
-
链接的时候,怎么去找这些函数和变量呢?-- 根据他们的函数和变量名字。但是每一个编译器都有自己的函数名修饰规则,在编译的时候会生成一个符号表,里面存放函数修饰后的名字。比如要调用test.cpp中写的一个Add函数,在汇编之后,生成了_ZAddii
-
这时候,在main.o中 去找声明中的函数的时候就会按照修饰后的名字去找该函数。
- 在C语言中,函数修饰之后还是原来的函数名,比如Add 修饰之后,符号表中的函数名字还是Add
- 而C++中,函数修饰之后就变了,在linux下 一般是:修饰符+原来的函数名+参数的首字母缩写
所以,C语言如果定义相同的函数名,在编译的时候就回出错,因为即使他们的参数不一样,修饰之后也不会生成不同的函数名,所以,相同的函数名字是不可以识别的。
而C++ 只要参数不同 生成的函数名是不同的,所以编译器就可以识别调用哪一个。这就是为什么C++支持重载而C语言不支持
如图:Linux下C语言的函数 编译修饰之后还是原来的函数名
而C++中的函数 编译修饰之后的函数名不一样了
Linux下 的函数名修饰规则一般是 _Z+X+函数名+参数首字母
其中_Z是一个前缀,X是一个数字表示 原函数名的长度
而在Windows下的函数名修饰规则比较复杂,了解一下即可:
C++程序如何调用C写的程序
我们以C++程序调用C程序写的静态库
和C程序调用C++程序写的库为例
准备两个项目:StackC项目:stack.c文件和stack.h文件
CallClib项目和一个test.cpp文件
StackC项目中的stack.c生成C程序写的静态库,stack.h作为头文件
然后CallClib项目用于测试调用C静态库,其中test.cpp要用到 栈这个数据结构,测试调用C写的栈
-
首先创建静态库
把.c文件包装成静态库:
然后生成解决方案
就可以在上一层目录的Debug文件夹里找到生成的.lib文件(静态库)
-
然后Cpp程序调用C的库
此时 cpp程序 想要用C语言写的库 从而调用栈
如何用?
-
首先包含头文件 让编译器知道 是存在这样的函数的
利用相对路径或者绝对路径,把库目录下的.h文件包含
注意 不要有中文
头文件包含了这些函数的声明,此时编译器是知道 存在这些函数的,认识这些函数名,可以编译成功。不过要去别的.o文件或者库去找 ,此时生成解决方案报的错误是链接错误
因为此时没有.o文件 也没有别的库 自然找不到这些函数的地址(注意这些函数是经过函数名修饰之后的函数)
然后我们就需要引入库,让编译器去库中找
-
引入库
填写库的名称
这就是告诉编译器 可以去这个库的符号表里去找上面那些函数的地址
然后编译一下 :
虽然我们已经配置了,但是还会出现错误,为什么??
因为这是cpp程序,包含头文件之后,头文件中声明的函数名会按照cpp的函数名修饰规则进行修饰,然后以修饰后的函数名去别的地方去找,但是此时静态库是C语言写的,C语言的函数名修饰之后 还是原来的函数名 所以静态库的符号表中的函数的名字 都是原来的函数名,就找不到对应的函数名的地址 出现链接错误
我们可能会怀疑是不是没导入成功(验证是否成功导入),只需要把库的.c文件 改成.cpp
然后重新生成解决方案,这时候这个库就是用cpp编译的。发现可以成功(可以自行验证)
那么如何用cpp程序调用C写的库呢?
我们只需要让cpp程序以c的函数命名规则去解读不就好了:
解决:因为有时候在c++工程中需要将某些函数按照c的风格去编译,这样c和c++的项目都可以使用: 在函数前面加extern "C", 意思就是告诉c++的编译器把该函数按照C的风格来编译。(因为c++是兼容c的,c++认识c的规则)
这样就是把 Stack.h头文件中的所有函数 都按照C的风格来编译 ,这样编译的时候,修饰后的函数名 就和 修饰前一样了。 可以发现生成解决方案成功
-
C程序如何调用C++写的程序
c程序调用c++的程序
准备两个项目:StackCPP项目:stack.cpp文件和stack.h文件
CallCPPLib项目和一个test.c文件
StackC项目中的stack.cpp生成C++程序写的静态库,stack.h作为头文件
然后CallCPPLib项目用于测试调用C++静态库,其中test.c要用到 栈这个数据结构,测试调用C++写的栈
把.cpp程序包装成静态库
过程和上面一样
在目标目录下生成静态库:
然后用一个C程序 包含头文件,链接用cpp写的静态库
生成解决方案:
与刚才面临类似的问题,会出现链接错误
这里是为什么呢?是因为C程序中展开Stack.h的头文件之后,按照C语言的函数修饰规则去修饰函数名,函数名修饰后还是原来的函数名
但是导入的库是c++写的,所以库里的函数名字经过修饰都不是原来的名字了,自然在链接的时候找不到对应函数的地址
那么这时候链接不上怎么改?
可以改c程序吗?可以在c程序中用extern "C++" 让C程序认识C++的规则吗?不可能,C是不认识C++的规则的
所以只能改库
把C++库里写的Stack.h文件以C的规则去编译,这样生成的库里面的函数名字就是按照C的规则去修饰的名字
然后重新生成解决方案
这时候回到C程序中生成解决方案
发现还是错误,这是为什么?
这是因为 在C程序中也引用Stack.h文件了
但是注意:Stack.h文件中是存在extern "C"命令的
但是C语言不支持这样的语法啊! 所以才会提示非法的字符串
所以就会报错!
解决方法:条件编译
如果当前是cpp文件,那么就执行extern "C"这个指令
否则不执行这个语句: __cplueplue 是C++的宏标识
如c++primer里所说:
此时,只有在.cpp文件中引用Stack.h的时候,extern"C"才会起作用
这样重新生成解决方案 可以通过
extern "C"的注意问题
如果使用C程序调用C++写的库,如果C++库中存在函数重载,也会出错
因为C不支持函数重载,所以要给C调用就不要写重载 或者 只extern没用重载的函数
标签:调用,函数,程序,C++,修饰,探究,cpp,重载 From: https://www.cnblogs.com/iiianKor/p/17982010