现在大家最讲模块化开发了,怎么算模块化,分成不同的类,分成不同的文件夹,高内聚,低耦合,这个当然算是。
从高层次讲,它们是在一起的,只是逻辑上的模块化,不是物理上的模块化,或者说不是彻底的模块化,彻底的模块化应该像一个辆自行车一样,车轮子是车轮子,车把是车把,都是可以拿下来的,都是可以换的。
QT插件就实现了这种要求,本质上,它就是DLL,然而,QT又对其进行了加强,通过虚函数作为接口,实现了动态的绑定(当然也可以自己实现这个过程,有现成的,方便很多),这样实现了接口与实现的彻底分离,实现了面对接口的开发,这应该是正确模块化开发的样子。
所谓的插件,只不过是重载了虚函数的dll,这跟抽象工厂类类似,这便是插件的原理。qt的插件可以说是一种动态库
在函数中,我们导入Interface接口文件,也就是插件接口文件,然后,加载动态库,获取具体实现类。
这样做的好处:定义开发范式,面向Interface编程,内部封装,模块和整体流程开发分离,提高开发效率。
应用场景QtCreator-IDE、WPS、visual studio、Nodepad++等等,都是采用这种开发方式。
创建工程的时间选择DLL工程即可:
下面是项目结构:
#ifndef STUDENTPLUGININTERFACE_H
#define STUDENTPLUGININTERFACE_H
#include <QtWidgets>
class StudentPluginInterface
{
public:
//析构函数
virtual ~StudentPluginInterface() {
}
//调用界面接口
virtual QWidget* getStudentWidget() = 0;
//调用普通接口
virtual QString getStudentInfo() = 0;
};
#define STUDENTPLUGININTERFACE_IID "com.test.studentplugin"
Q_DECLARE_INTERFACE(StudentPluginInterface, STUDENTPLUGININTERFACE_IID)
#endif // STUDENTPLUGININTERFACE_H
注:
1.虚析构函数一定要定义,这有助于确保利用基类的指针访问子类时,可以调用子类的析构函数,以避免内存泄漏
遗憾的是,大多数C++编译器并没有警示信息
2.Q_DECLARE_INTERFACE宏,将类定义为接口
3.DEVICEPLUGININTERFACE_IID 应该是与包名格式类似的唯一字符串,可以根据自己的喜好更改
头文件StudentPluginExport.h:
#ifndef DLLEXAMPLE1_H
#define DLLEXAMPLE1_H
#include "dllexample1_global.h"
#include "studentplugininterface.h"
#include "StudentWidget.h"
#include <QObject>
class STUDENTPLUGIN_EXPORT StudentPluginExport : public QObject, public StudentPluginInterface
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "com.test.studentplugin")
Q_INTERFACES(StudentPluginInterface)
public:
StudentPluginExport();
//析构函数
~StudentPluginExport();
//调用界面接口
QWidget* getStudentWidget();
//调用普通接口
QString getStudentInfo();
};
#endif // DLLEXAMPLE1_H
1.添加接口类的头文件
2.确保导出类StudentPluginExport继承了QObject和StudentPluginInterface
3.添加必要的宏,以便将库识别为插件
Q_OBJECT Qt宏,以便使用Qt特定的功能
Q_PLUGIN_METADATA(IID “com.test.studentplugin”) 用于添加关于插件的元数据
Q_INTERFACES(StudentPluginInterface) 用于声明插件中实现的接口
CPP文件StudentPluginExport.cpp:
#include "StudentPluginExport.h"
StudentPluginExport::StudentPluginExport()
{
}
StudentPluginExport::~StudentPluginExport()