本文已参与「新人创造礼」活动,一同敞开掘金创造之路。
- 导入库对应的头文件
- 在CPP文件中调用函数
- 在链接程序时加上动态库作为参数
假设demo.cpp中需求用到动态库libadd.so
中的某个函数,可能是int add(int x, int y)
,那么咱们编译时就需求链接上libadd.so,
gcc参数中-L./libs
指定了当时目录下的libs目录为库的目录,-ladd
指定了libadd.so动态库文件,注意这里并未运用全称,让编译器主动适配即可。
// 该办法为静态导入办法(在程序未运行时完结导入)
gcc demo.cpp -o demo -L./libs -ladd
在运行时加载动态库并获取目标指针(QLibrary)
// 导入动态库
QLibrary m_library;
m_library.setFileName("./libs/libadd.so");
assert(m_library.load());
// 获取函数指针
typedef int (*FUNC_ADD)(int, int);
FUNC_ADD add = (FUNC_ADD)m_library.resolve("add");
assert(add);
// 愉快的运用add函数
int a = add(125, 125);
qDebug() << a;
本贴要点:在动态库中调用宿主进程的目标办法
先温习下两个概念:纯虚函数和虚函数表
- 纯虚函数在类中界说后是能够不用完成的,子类如承继含有纯虚函数的类有必要完成该类所有的纯虚函数。纯虚函数可作接口运用。
- C++拥有虚函数表(V-Table),存储着虚函数地址的表。
假设动态库需求调用宿主进程的目标办法,在动态库编译时时无法获取到宿主程序该目标的完成的,所以依照正常逻辑是无法编译经过的。但是经过上边有用的温习能够知道纯虚函数在调用时可无需完成(在运行时经过查询虚函数表后获取实践地址),这样就能够顺畅的完结了编译,当动态库被加载进宿主进程后就能够正常调用目标的办法了。
还是以add办法为例写一个Demo
宿主程序:
#ifndef __MATH_H__
#define __MATH_H__
// 接口界说
class IMath
{
public:
virtual int add(int x, int y) = 0;
};
typedef void (*FUNC_SET_OBJ)(void*);
class Math: public IMath
{
public:
Test() {
m_library.setFileName("./libs/libtest.so");
assert(m_library.load());
FUNC_SET_OBJ setObj= (FUNC_SET_OBJ)m_library.resolve("setObj");
assert(setObj);
// 将Math实例传递给动态库
setObj(this);
}
int add(int x, int y) ovdrride {
return x + y;
}
private:
QLibrary m_library;
}
#endif
然后将接口做成一个独立的头文件imath.h
,用来给动态库调用
#ifndef __IMATH_H__
#define __IMATH_H__
class IMath
{
public:
virtual int add(int x, int y) = 0;
};
#endif
动态库程序(libtest.cpp):
void setObj(void* obj) {
IMath* math = static_cast<IMath*>(obj);
qDebug() << math->add(125, 125);
}
将动态库程序编译后放入libs目录下给宿主程序调用,在宿主程序中实例化Math类,并调用其Test办法,在Test办法中会加载动态库,并将Math实例的指针传递给动态库,动态库将Math实例强转为接口类型并调用其中的纯虚函数add()
。