目录
一、插件
1.1 插件概念
插件是一种(遵循一定规范的应用程序接口编写出来的)程序,定位于开发实现应用软件平台不具备的功能的程序。插件必须依赖于应用程序才能发挥自身功能,仅靠插件是无法正常运行的;相反地,应用程序并不需要依赖插件就可以运行,这样一来,插件就可以加载到应用程序上并且动态更新而不会对应用程序造成任何改变(热更新)。插件就像硬件插卡一样,可以被随时删除、插入和修改,所以结构很灵活,容易修改,方便软件的升级和维护。
1.2 插件和动态库的区别
两者都是用于封装部分功能的实现,并降低模块代码耦合度。但其实插件也是被部署为动态库的形式,但是和传统的动态库还是有一些差别的。
插件:插件主要面向接口编程,无需访问.lib文件,热插拔、利于团队开发。即使在程序运行时.dll不存在,也可以正常启动,只是相应插件功能无法正常使用而已;
动态库:动态库需要访问.lib文件,而且在程序运行时必须保证.lib存在,否则无法正常启动;
1.3 Qt提供了两种API用于创建插件
-
一种是高阶API,用于扩展Qt本身的功能:例如自定义数据库驱动、图像格式、文本编码、自定义样式等等;
Qt 有很多可以扩展的接口。例如,您可以为样式、数据库驱动程序、文本编解码器和图像格式添加插件。Qt 的可扩展性有很多好处。首先,它让 Qt 更加耐用,因为它可以适应新技术。还可以让 Qt 更轻便,因为不需要的插件不需要部署。这也确保了你可以继续使用 Qt 的应用编程接口,即使你需要针对特殊的技术。
-
一种是低阶API,用于扩展Qt应用程序;
1.4 Qt低阶API扩展Qt应用程序插件
对于 Qt 应用程序来说,插件只是类的另一个实例。可用的方法由接口类决定。一个接口类通常只包含纯虚方法,所以接口类中没有实现任何函数。然后,插件继承了QObject类和接口类,并实现了所有具有特定功能的方法。当应用程序加载一个带有QPluginLoader类的潜在插件时,它会得到一个QObject指针。通过尝试使用qobject_cast将给定的对象转换为接口类,应用程序可以判断插件是否实现了预期的接口,是否可以被视为实际的插件。
为了让QPluginLoader正常工作,接口类必须通过使用Q_DECLARE_INTERFACE宏声明为接口,插件必须通过使用Q_INTERFACES宏声明它们实现了一个接口。这两个宏使您能够安全地将给定的插件匹配到正确的界面。这是 Qt 信任插件必须满足的一系列标准中的一步。
Qt插件开发:
主要分为主程序部分和插件程序部分
主程序部分:定义插件的接口并提供插件的管理器用于管理插件的加载与使用。
插件程序部分:按照主程序中定义的插件接口来定义插件,实现插件功能,生成共主程序部分调用方的插件。
主程序开发流程:
1.定义一组用于与插件通信的接口(C++纯虚函数的类)
2.使用Q_DECLARE_INTERFACE()宏来告诉Qt的元对象系统有关接口的情况。
3.在应用程序中使用QPluginLoader加载插件。
4.使用qobject_cast()来测试插件是否实现指定接口。
Qt插件程序部分开发流程
1.声明一个继承自QObject和插件接口的插件类
2.使用Q_INTERFACES()宏告诉Qt元对象系统有关接口的情况;
3.使用Q_PLUGIN_METADATA()宏导出插件
二、Qt插件代码实战
2.1 主程序部分
定义接口类:
#pragma once
#include<QObject>
class CalculatInterface
{
public:
//插件:面向接口 定义一组用于与插件通信的接口(只有纯虚函数)
virtual ~CalculatInterface() {};
virtual int add(int a, int b) = 0;
virtual int mins(int a, int b) = 0;
virtual int mul(int a, int b) = 0;
virtual int devid(int a,int b) = 0;
};
//插件唯一的标识符
#define CalculatInterface_iid "Plugin_CalculatInterface_iid"
//告诉元对象系统接口 将类声明为接口
Q_DECLARE_INTERFACE(CalculatInterface, CalculatInterface_iid)
主程序调用插件:
void LogTest::TestPlugin()
{
I