插件类其实就是接口类的子类,用于实现接口类。
该Interface必须是虚基类,且所有函数(除了析构)都是虚函数。
而所谓的plugin就是继承该虚基类和QObject的子类。
当程序调用该plugin的某个函数时,是通过该plugin的虚基类在运行时动态绑定至子类的vtable执行的。
1、编写接口类
创建项目 MyPlugin1,最终用于生成插件 MyPlugin1.dll
个人习惯,勾选小写,其他全部默认
最终项目中,多出一个*_global.h文件,此文件不需任何更改。
添加接口类头文件 MyInterface.h
MyInterface.h
#pragma once #include <QObject> #include <opencv.hpp> /** * @brief * 接口类格式: * 1、虚析构 * 2、其他函数纯虚 * 3、无成员变量 */ class MyInterface { public: //公开 virtual ~MyInterface(){} virtual void medianFilter(const cv::Mat& inputImg, cv::Mat& outputImg) = 0; }; //声明接口 #define MyInterface_IID "com.Interface.MyInterface" Q_DECLARE_INTERFACE(MyInterface,MyInterface_IID)
2、实现接口类
myplugin1.h
#pragma once #include "myplugin1_global.h" #include "MyInterface.h" //引入接口类 /** * @brief * 插件类其实就是接口类的子类,用于实现接口类 * 格式: * 1、继承QObject * 2、继承接口类 */ class MYPLUGIN1_EXPORT MyPlugin1 :public QObject ,public MyInterface { //宏3联 Q_OBJECT Q_PLUGIN_METADATA(IID MyInterface_IID) //描述插件元数据 Q_INTERFACES(MyInterface) //本类要实现的接口 public: MyPlugin1(); ~MyPlugin1(); //实现的虚函数 virtual void medianFilter(const cv::Mat& inputImg, cv::Mat& outputImg) override; };
myplugin1.cpp
#include "myplugin1.h" MyPlugin1::MyPlugin1() { } MyPlugin1::~MyPlugin1() { } void MyPlugin1::medianFilter(const cv::Mat& inputImg, cv::Mat& outputImg) { cv::medianBlur(inputImg, outputImg, 5); }
运行,会在Debug或Release中生成dll
3、新建程序,PluginDemo
在exe目录里新建plugins文件夹,把之前生成的插件dll放入其中。
【注意】dll是区分编译器版本、debug/release的,exe需使用对应的dll。类似VS不能用MinGW编译的dll。
把之前的接口文件放入项目路径,并添加到VS项目中
运行结果
main.cpp
#include <QtCore/QCoreApplication> #include <QDir> #include <QPluginLoader> #include"MyInterface.h" //引入接口类 int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); //加载插件 QDir pluginsDir = QDir(qApp->applicationDirPath()); //exe路径 if (!pluginsDir.cd("plugins")) //若无法进入plugins文件夹则返回 { return -1; } int counter = 0; //统计有效插件,无则返回 for each (QString pluginName in pluginsDir.entryList(QDir::Files)) //遍历plugins中的插件(库) { if (QLibrary::isLibrary(pluginName)) //是否是库文件 { QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(pluginName)); //加载插件 if (qobject_cast<MyInterface*>(pluginLoader.instance())) //是否与插件接口兼容 { //一些操作,如将插件展示到界面等 //由于只是讲解插件的基本知识,此段仅参考即可。可以直接指定具体的dll进行函数调用。 counter++; } } } if (0==counter) //无有效插件则返回 { return -1; } //直接指定具体的dll进行函数调用 QPluginLoader pluginLoaderNow(qApp->applicationDirPath() + "/plugins/MyPlugin1.dll"); //加载插件 MyInterface* plugin = qobject_cast<MyInterface*>(pluginLoaderNow.instance()); //实例化,接口类对象 cv::Mat src, dst; src = cv::imread("C:/line.bmp"); plugin->medianFilter(src, dst); //调用函数 cv::imshow("原图", src); cv::imshow("插件里实现的中值滤波", dst); return a.exec(); }