一、C++函数重载
1、编写代码
(1)sum.h
#ifndef __SUM_H__
#define __SUM_H__
int sum(int a, int b);
float sum(float a,float b);
#endif
(2)sum.cpp
#include "sum.h"
int sum(int a, int b) {
return a + b;
}
float sum(float a, float b) {
return a + b;
}
(3)main.cpp
#include <iostream>
#include "sum.h"
using namespace std;
int main()
{
cout << "1+4 = " << sum(1,4) << endl;
cout << "1.1+4.4 = " << sum(1.1f,4.4f) << endl;
return 0;
}
2.编译运行
3.使用nm
命令查看可执行文件中的符号表
// nm 可执行文件名 或 目标文件名
nm a.out
4.C++中的函数重载实质
这两个函数名看是经过了C++的名称修饰(name mangling),因为在C++中,函数重载会导致相同的函数名被修改以包含参数类型信息,以用来区分同名函数。
(1) _Z3sumff
:这是一个函数名,sum(float a, float b)
经过了C++的名称修饰,表示一个接受两个float参数的函数。
(2) _Z3sumii
:同样,sum(int a, int b)
这个函数名也经过了C++的名称修饰,表示一个接受两个int参数的函数。ii
表示两个参数都是int类型。
结论:c++里面的函数重载不是真的说可以同名,g++在编译的时候将这两个sum的名字给换掉了
5.函数重载的使用时机
1.必须在同一个作用域中才有效
2.函数的名字必须相同
3.参数不一样
(1)参数个数不用
(2)参数类型不一样
(3)参数类型一样,但是参数顺序不一样
4.函数重载跟返回值没有关系
二、C/C++混合 编程
1、为什么要这样做:
混合编程(Mixing C and C++ Programming)是指在同一个程序中同时使用 C 和 C++ 语言的特性,这在实际项目中是非常常见的。
- 模块化编程:将
sum.c
编译成动态链接库后,可以将函数sum
独立地组织成一个模块,这样可以方便地在其他程序中复用。 - 隐藏实现细节:动态链接库中只包含了函数的二进制实现,而隐藏了具体的源代码。这样可以保护代码的知识产权,并且在使用库的程序中无需了解具体实现细节。
- 提高可维护性:动态链接库可以独立编译和更新,这样在更新库时只需替换动态链接库文件,而不需要重新编译使用库的程序。
- 简化编译和链接过程:在编译
main.cpp
文件时,通过-L
和-l
选项指定了库文件的路径和名称,编译器会自动查找并链接指定的动态链接库。这样可以简化编译和链接的过程,减少了手动操作的复杂性。 - 跨语言兼容性:使用动态链接库的方式可以实现 C 和 C++ 之间的互操作,因为动态链接库中的函数可以以 C 的方式进行链接,并且可以在 C++ 中调用。
**总的来说:**使用混合编程和动态链接库的方式能够充分发挥 C 和 C++ 语言的优势,提高项目的效率、可维护性和可扩展性,是现代软件开发中常见的实践之一。
2、好处和作用:
-
模块化编程:将
sum.c
编译成动态链接库后,可以将函数sum
独立地组织成一个模块,这样可以方便地在其他程序中复用。 -
隐藏实现细节:动态链接库中只包含了函数的二进制实现,而隐藏了具体的源代码。这样可以保护代码的知识产权,并且在使用库的程序中无需了解具体实现细节。
-
提高可维护性:动态链接库可以独立编译和更新,这样在更新库时只需替换动态链接库文件,而不需要重新编译使用库的程序。
-
简化编译和链接过程:在编译
main.cpp
文件时,通过-L
和-l
选项指定了库文件的路径和名称,编译器会自动查找并链接指定的动态链接库。这样可以简化编译和链接的过程,减少了手动操作的复杂性。 -
跨语言兼容性:使用动态链接库的方式可以实现 C 和 C++ 之间的互操作,因为动态链接库中的函数可以以 C 的方式进行链接,并且可以在 C++ 中调用。
**总的来说:**使用动态链接库的方式能够提高代码的可维护性、复用性和安全性,同时简化编译和链接的过程,使得混合编程更加方便和灵活。
1.C调用C++的函数
1、编写代码
(1)sum.h
#ifndef SUM_H
#define SUM_H
int sum(int a, int b);
#endif
(2)sum.cpp
#include "sum.h"
int sum(int a, int b) {
return a + b;
}
(3)main.c
#include <stdio.h>
#include "sum.h"
int main() {
int result = sum(10, 20);
printf("Sum: %d\n",result);
return 0;
}
2、编译
(1)先将CPP
的库编译成.so文件
g++ -shared -fpic -o libsum.so sum.cpp
gcc main.c -L./ -lsum
-shared: 生成一个共享对象文件(也称为共享库或动态链接库)。共享对象文件可以被多个程序共享加载,它们在内存中只会存在一份拷贝,因此节省了系统资源。
-fpic: 生成位置无关的代码, 可以在内存中的任何位置运行 。在生成共享对象文件时,通常需要使用 -fpic 选项,以确保在程序运行时能够正确加载共享库并执行其中的代码。
-o: 指定输出文件的名称。
-L./:链接器选项,用于指定要搜索库文件的路径。. 表示当前目录,所以 -L./ 意味着在当前目录中搜索库文件。
-lsum:链接器选项,用于指定要链接的库文件的名称。在这里,-lsum 意味着链接名为 libsum.so 的动态链接库。
libsum.so: 生成的共享对象文件的名称,lib为固定前缀!
无法执行,并且显示“对sum
未定义的引用”。这是因为,C++在编译过程中修改了函数名。使用nm
命令查看函数名:
函数名被更改!
3、链接
生成了.so
文件后,它已经包含了编译后的目标代码,而不再依赖于原始的源代码文件。意思是 .so
文件中包含了编译后的目标代码,其中包括了函数的实现。
所以,使用gcc
去编译main.c
文件,当系统去查看sum
的函数声明时,发现找不到sum
函数,因为sum
函数在编译阶段就已经被c++
改名为了_Z3sumii
!
解决方案1:
未定义的引用是因为sum
函数被改名为了_Z3sumii
,而sum.h
文件,和main.c
文件中,又找不到sum
函数的定义。
此时,将main.c文件和sum.h文件中的sum
函数调用和声明改为_Z3sumii
就行了。
main.c
#include <stdio.h>
#include "sum.h"
int main() {
int result = _Z3sumii(10, 20);
printf("Sum: %d\n",result);
return 0;
}
sum.h
#ifndef SUM_H
#define SUM_H
int _Z3sumii(int a, int b);
#endif
编译通过,运行成功!
解决方案2:使用 __cplusplus
和 extern
将C环境中的C++函数声明为:C++语言中的函数。
2.C++调用C的函数
1、编写代码
1.sum.h
#ifndef SUM_H
#define SUM_H
int sum(int a, int b);
#endif
2.sum.c
#include "sum.h"
int sum(int a, int b) {
return a + b;
}
3.main.cpp
#include <iostream>
#include "sum.h"
int main() {
int result = sum(10, 20);
std::cout << "Sum: " << result << std::endl;
return 0;
}
2、编译运行
gcc -shared -fpic -o libsum.so sum.c
g++ main.cpp -std=c++11 -L./ -lsum
结果:
3、解决方案:
通过 um
可以查看到使用 gcc
编译过的 sum.c
是没有被改变名字的。
虽然库中sum
函数名没有被改变,但是,使用 g++
编译 main.cpp
的时候,编译器又将 sum
函数的名字改变了,导致系统又查找不到 sum
函数的声明和定义。
解决:使用 __cplusplus
和 extern
将C++环境中的C函数声明为:C语言中的函数。
#ifndef SUM_H
#define SUM_H
#ifdef __cplusplus
extern "C" {
#endif
int sum(int a, int b);
#ifdef __cplusplus
}
#endif
#endif
在 C++ 中,当编译器编译代码时,会自动定义一个名为 __cplusplus
的宏,并赋予一个非零值。而在编译 C 代码时,__cplusplus
宏是未定义的,即:编译 C 代码时,不会定义 __cplusplus
宏。
因此,通过使用 #ifdef __cplusplus
,可以在 C++ 环境下执行特定的代码,而在 C 环境下则可以执行不同的代码。这种条件编译的方式使得我们可以编写可以同时被 C 和 C++ 编译器正确处理的代码。
在 C++ 中,可以使用 extern "C"
来声明 C 风格的函数,以便能够在 C++ 中正确地链接和调用这些函数。而在 C 中,不需要这样的声明,因此可以使用 #ifdef __cplusplus
来包含这些额外的声明,以确保它们只在编译 C++ 代码时被编译。
执行
执行通过!