DLL,在windows和linux下都用,但是不太相同,因为微软的DLL的内存分配和普通编译成为函数之间的内存格式是不一样的,于是有了__declspec(dllexport)和__declspec(dllimport) ,前者输出DLL中的函数,后者调用的时候使用;相信在windows底下封装过DLL经验的人对于这两个东西还是很熟悉的。偶尔去掉它们,其实也不一定会出问题,但是在多线程的重复调用DLL时,就会有问题的。对于Windows和linux统一版本的DLL的封装就可以用下面的宏来解决了。
#ifdef WIN32
#ifdef DLL_EXPORTS
#define EXPORT_CLASS __declspec(dllexport)
#define EXPORT_API extern "C" __declspec(dllexport)
#else
#define EXPORT_CLASS __declspec(dllimport )
#define EXPORT_API extern "C" __declspec(dllimport )
#endif
#else
#define EXPORT_CLASS
#define EXPORT_API
#endif
如果要输出函数 int func()的话,对于函数的输出的声明为
EXPORT_API int func();//DLL_EXPORTS这个宏作为是输出DLL,还是调用DLL的开关
都知道,如果DLL需要输出函数的,肯定要求是全局或者静态的函数。那么如果要输出多个函数的话,意味着要写很多的全局函数。对于做惯了C++面向对象开发的人来说,这肯定不是一个很舒服的写法;而且你提供给别人的接口也很难保证干净,因为你不可避免的会将你很多不愿意输出的函数也写在你的.h文件中。那么这里给出一种解决方案。
这个解决方案依赖的就是函数的继承,定义一个空的接口类Class A。
class EXPORT_CLASS A
{
public:
virtual int init() = 0;
virtual int process(const char * param) = 0;
virtual int finish() = 0;
};//那么A是一个纯虚的函数呢
在你的DLL中,封装真正的目标类B
///.h file
class B :public A
{
public:
virtual int init() ;
virtual int process(const char * param) ;
virtual int finish() ;
private:
unsigned int m_param;
public:
//*********//
// add your functions or params which don't need to be showed out here
};
EXPORT_API A*Create();//输出Create这个全局的函数
//.cpp file
A* Create()
{
B *_pdll =new B();
return _pdll;
}
//add your realization of Class B 's Functions,such as init();process(const char *)……
那么外部Load这个DLL的之后,取得函数Create的指针,并执行该函数,那么产生的对象实体是B,返回的类型是A。外部调用的时候看到永远是Class A 中声明的纯虚函数而已。这样子,接口更简单,调用的时候只需要执行一个函数之后就不用再频繁的获取函数的指针。大大的简化的操作的简单性,也便于并行开发。
PS:对于windows下的DLL封装的函数调用时,或者想通过DLL将函数输出时,任何非基本类型的参数,都需要用__declspec(dllexport)和__declspec(dllimport) 。这具体是什么含义呢,就是如果参数里面出现了类(非基本的类型,非int ,char,bool之类的),都需要用上面两个声明来定义这个参数的类。例如DLL永远不能输出参数string类型,因为它的声明中没有用到上面的两个东东。DLL输出函数int func(classTmp * t_param);那么要求classTmp的定义一定是class EXPORT_CLASS classTmp{ /***********/ };