回调函数和动态库
在编写代码时,使用动态库可以提高代码项目的可维护性。但在使用动态库时存在需要对使用外部函数作为输入的时候,此时需要使用回调函数进行回调,完成代码的具体功能。
- 生成动态链接库
- 使用回调函数完成链接库
1. 生成动态链接库
由于C++编译后函数名会发生变化,所以建议将C++封装成C的接口形式。使用extern "C"
将接口封装成C语言的形式。
#ifdef __cplusplus
extern "C" {
#endif
__declspec(dllexport) int dll_add(int a, int b); // 简单的加法,和不同的昂发一样,不做实现
#ifdef __cplusplus
}
#endif
其中__declspec(dllexport)
表示将它的所有成员函数和静态数据成员都导出。但dll仅在Windows下才能使用,所以建议头文件添加代码
#ifdef __linux__ //Linux platform
#define ADD extern
#elif _WIN64
// #ifdef ALG_WINDOWS //Windows platform
#ifndef ADD
#define ADD __declspec(dllexport)
#else
#define ADD __declspec(dllimport)
#endif // !__JNAINTERFACE__
// #endif
#endif
// 后续可以使用ADD表示__declspec(dllexport)
该声明可以再Linux中生成.so文件,在Windows中生成.dll文件。
将代码完成后,生成动态库。在Linux下生成动态库的方法参考博客。 Windows下可以使用Visual Studio生成。
2. 使用回调函数完成链接库
使用回调函数可以使用函数指针完成,也可以使用functional库完成。
首先构建动态链接库
#include<functional>
#ifdef __linux__ //Linux platform
#define ADD extern
#elif _WIN64
// #ifdef ALG_WINDOWS //Windows platform
#ifndef ADD
#define ADD __declspec(dllexport)
#else
#define ADD __declspec(dllimport)
#endif // !__JNAINTERFACE__
// #endif
#endif
typedef function<int(int, int )> Fun;
#ifdef __cplusplus
extern "C" {
#endif
ADD int dll_add(Fun fun, int a, int b);
#ifdef __cplusplus
}
#endif
调用dll需要引入.h文件、.lib文件和.dll文件,其中.dll文件需要放在当前运行的目录下。
#include<functional>
int add(int a, int b)
{
return a + b;
}
int main()
{
std::function<int(int, int )> f = std::bind(add, std::placeholders_1, placeholders_2);
auto res = dll_add(f, 1, 2);
}
当然调用的文件可能是类的成员函数,所以需要将其修改为
#include<functional>
class Add
{
public:
int add(int a, int b);
};
int Add::add(int a, int b)
{
return a + b;
}
int main()
{
Add test;
std::function<int(int, int )> f = std::bind(&Add::add, &test, std::placeholders::_1, placeholders::_2); // std::placeholders表示未知的输入参数
auto res = dll_add(f, 1, 2);
}
参考博客
在 C++ 类中使用 dllimport 和 dllexport
类中使用 dllimport 和 dllexport](https://learn.microsoft.com/zh-cn/cpp/cpp/using-dllimport-and-dllexport-in-cpp-classes?view=msvc-170)