从Linux and Windows 的动态库中引入类的方法
一般从Windows的动态库引入类的方法比较简单,只需要在DLL的类的申明出加入EXPORT就可以,但是这种方法只限于编译的时候引入DLL,就是通过Lib的方式引入DLL,但是很多情况下需要在程序的运行期来引入Dll,就像在程序运行的时候使用LoadLibrary获得动态库,然后通过GetProcAddr来取得函数在库中的地址。怎样能够在运行的时候从动态库中引入类的申明呢?
首先在Windows下看一看如何做:
我们知道,在DLL中的类实际上只是一个类型的申明,他并没有实际的地址,所以希望通过地址来直接取出一个类的方法是无效的。虽然直接取不行,但是可以使用间接的方法,我们可以在DLL中创建一个全局函数或者静态函数,用这个函数来创建一个类的对象,这样我们就可以使用该类了。
看这一段申明DLL的代码:
这个演示的类有两个成员函数,一个是init()函数,用来初始化成员变量,另一个是print()函数,用来输出成员变量。为了使这个类能够被外部程序使用,我们为她添加了两个成员函数,请见下面:
1.Create()函数,他用来创建一个MyClass的对象,并且返回一个指向该类的指针。
2.Destroy()函数,他用来销毁前面创建的MyClass的对象指针并释放资源。
通常一个类的所有成员函数都要在外部一一申明这样才可以使用,这里我们使用了一个技巧,就是把所有的Public属性的成员函数全部申明成virtual函数,利用虚函数自动与对象动态帮定的特性,这样在使用时直接引用对象的成员方法就可以了。
#define EXPORT __declspec(dllexport)
class MyClass{
int x;
int y;
public:
//把Create和Destroy方法申明为静态的和可供符号输出的
EXPORT static MyClass * Create()
{
return new MyClass();
}
EXPORT static void Destroy(MyClass * mc)
{
delete mc;
}
virtual void init();
virtual void print();
};
在主程序使用动态库中的类的方法:
首先定义函数指针类型
typedef MyClass* (*CreateMyClass)();
在主函数中:
//先LoadLibrary读取DLL库
HINSTANCE hInstance = LoadLibrary("MyDll.dll");
//用普通的GetProcAddress方法取得Create函数的地址;
CreateMyClass createMC =
(CreateMyClass)(GetProcAddress(hInstance,
MAKEINTRESOURCE(1)));
//然后用Create函数创建对象
MyClass *d = createMC();
//下面就可以使用该对象了。
d->init();
d->print();
下面介绍Linux下的动态库中的类的输出方法:
Linux的动态库一般称为共享库(shared library),其特征是以“.so”为文件的扩展名。
同WIindows一样Linux下的动态库的类的输出也是要依靠动态库中的一个全局函数或者静态函数,与Windows中的输出方法不一样的地方是Linux没有__declspec(dllexport)关键字。但他必须把要输出的函数申明为extern “C”类型的,这样在GetProcAddr时候才能找到该地址
实例的Shared Library代码如下:
#include <stdio.h>
class MyClass{
int x;
int y;
public:
virtual void init();
virtual void print();
};
extern "C" {MyClass * Create()
{return new MyClass();
}
}
//1-2)linux shared library cpp file
#include "MyDll.h"
void MyClass::init()
{
x=3;
y=4;
}
void MyClass::print()
{
printf("%d%d\n",x,y);
}
主程序文件如下:
#define SHARED
#define SOFILE "./mydll.so"
#include <iostream>
#include "dlfcn.h"
#include "Mytest.h"
using namespace std;
MyClass* (*CreateClass)();
int main()
{
void *dp;
char *error;
dp = dlopen(SOFILE,RTLD_LAZY);
if(dp == NULL)
{
cout<<"can't open file"<<endl;
}
CreateClass =(MyClass*(*)())dlsym(dp,"Create");
error = dlerror();
if(error)
{
cout<<"can't get symbol"<<endl;
}
MyClass *d = CreateClass();
d->init();
d->print();
linux makefile文件内容如下:
all:
gcc -c mydll.cpp
gcc -shared -o mydll.so mydll.o
g++ -c mytest.cpp
g++ -rdynamic -s -o mytest mytest.cpp -ldl