QT调用dll及dll导出类的注意点(dll地狱等)

不说导出那几种方式了,一般我们自己的工程只要一种就行:

extern "C" _API IExport* CreateExportObj();

其中加不加 __stdcall __cdecl 都行。如果要给别人用就一般用 __stdcall。

命名更改规律一图搞定:

LYJ博客

再来说说dll导出类。

一般只要类前面加上 _API就行了,定义如下:

#ifdef MYDLL
// MYDLL 是dll工程定义的,app工程不定义
#define _API __declspec(dllexport) 
#else
#define _API __declspec(dllimport) 
#endif
class _API myClass
{
public:
   int func(void){return 0;}
private:
   int i;
}

这样在app中引入lib和h就跟调用本地cpp一样方便。

但是,这里容易出问题,出来一个叫dll hell,就是dll地狱问题。这个问题的现象就是,你改动了这个dll,如果app没有重新编译容易崩溃!原因很多人都讲了可以看下:https://blog.csdn.net/qwertyupoiuytr/article/details/53999586

那么如何避免更改dll容易崩溃的问题呢?这不是违背只更换dll就可以更新这个初衷了吗?


方法1、


使用虚函数(多态性。java是仿照c++,不是c++仿照java)导出方法,并且定义2个单独的函数来创建和销毁该类:


#ifdef MYDLL
#define _API __declspec(dllexport)
#else
#define _API __declspec(dllimport)
#endif

class _API ExportInterface
{
public:
    virtual void foo() = 0;
};

// 定义单独函数初始化实例,也可以单例模式
extern "C" DLL_API ExportInterface*  getInstance();
#define MYDLL
#include "dllExample.h"

// 该函数是示例,实际最好要做成单例模式,防止多次new,单例用法参考: 
// https://labisart.com/blog/index.php/Home/Index/article/aid/227
extern "C" DLL_API ExportInterface* getInstance()
{
    ExportInterface* pInstance = new ExportClass();
    return pInstance;
}

具体实现的子类定义如下:

class ExportClass: public ExportInterface
{
pirvate:
    std::string x; //由于外部代码对此不可见,此处的std::string是安全的。
public:
    void foo();    //函数体在dllExample.cpp中实现
};


使用的时候,只要 getInstance()->foo()就可以调用了类的函数。

虚函数其实也有弊端,如果修改的dll,改变了虚函数原来的顺序,那么调用也会出问题。


方法2、

在接口不变的情况下,使用 extern "C"是一个方法,


方法3、

做成插件。只要接口不变,类怎么折腾都不会引起dll hell问题!


方法4、

导出类情况下,把private隐藏起来,做成一个指针,具体可以参考Qt的D指针方法,例如

class Myclass{
public :
int api(){return m_a;}
private:
int m_a;
};

// 把m_a隐藏起来
class MyclassPrivate;
class Myclass{
public :
int api();
private:
// 只维护一个私有指针
MyclassPrivate *pri;
};

// cpp定义:
class MyclassPrivate{
int m_a;
};
Myclass(){
// 分配自己的内部私有数据
pri = new MyclassPrivate;
}
int Myclass::api()
{
return pri->m_a;
}


QT调用dll也比较简单:

typedef CoreFrame* ( *icoreFrameInit)(QWidget *);

QLibrary core("CoreFramed2.dll");
frame = (icoreFrameInit)core.resolve("coreFrameInit");


参考:

https://www.cnblogs.com/dongsheng/p/3924287.html

https://blog.csdn.net/xiaominggunchuqu/article/details/72837760

https://www.cnblogs.com/JingJ/p/4442286.html

https://blog.csdn.net/qwertyupoiuytr/article/details/53999586

https://blog.csdn.net/amnes1a/article/details/69055858    

本文为3YL原创,转载无需联系,但请注明来自labisart.com。

原创文章不易,如果觉得有帮助,可打赏或点击右侧广告支持:

查看打赏记录

发表评论请遵守党国法律!后台审核后方可显示!
  • 最新评论
  • 总共0条评论
  • Blog v1.1© 2024 labisart.com 版权所有 | 联系:labartwork@163.com