QT插件加载与相关宏定义

57 篇文章 2 订阅

1. 应用程序与插件加载

对于QT应用程序来讲,一个插件就是一个类的实例。插件的可用的方法由对应的接口类来决定。接口类仅仅包含纯虚函数,也就是说接口并不实现任何方法函数。插件通过继承QObject且继承对应的接口类来实现内部的具体函数功能。当应用程序用QPLuginLoader类加载可能的插件时,就会得到一个指向QObject的指针。通过将这个对象用qobject_cast 强制封装成接口类,应用程序就会分辨出插件是否真正实现了期望的接口,如果是就被加载成正确的插件。

要让QPluginLoader正确工作需要两个条件:1.插件接口类需要用宏Q_DECLARE_INTERFACE来声明;2.插件类本身也需要用Q_INTERFACES宏来声明表示实现了接口。这两个宏能够安全地让插件类与插件接口类匹配。事实上,QT在加载插件时有一个如下的检测标准,如果不满足,插件就不能正确加载。检查标准列表:

  1. 构件插件与应用程序的Qt版本必须一致,也就是major与minor数字一样;
  2. 构件插件与应用程序必须在同一个平台,同一操作系统,同一编译器中构建;
  3. Qt库配置选项在插件与应用程序中一样,且以共享模式编译。
    1. Q_DECLARE_INTERFACE接口类声明

比如,我们已经定义了AddInInterfaceBase接口类,可以如下声明接口类,

Q_DECLARE_INTERFACE(AddInInterfaceBase, AddInInterface_CurrentVersion)

该宏定义在qobject.h中,其实就是定义了3个模板内联函数,展开如下,

# define Q_DECLARE_INTERFACE(IFace, IId) \

    template <> inline const char *qobject_interface_iid<IFace *>() \

    { return IId; } \

    template <> inline IFace *qobject_cast<IFace *>(QObject *object) \

    { return reinterpret_cast<IFace *>((object ? object->qt_metacast(IId) : nullptr)); } \

    template <> inline IFace *qobject_cast<IFace *>(const QObject *object) \

    { return reinterpret_cast<IFace *>((object ? const_cast<QObject *>(object)->qt_metacast(IId) : nullptr)); }

#endif

2.Q_INTERFACES插件实现接口声明

Q_INTERFACE宏定义在qobjectdef.h中

#define Q_INTERFACES(x) QT_ANNOTATE_CLASS(qt_interfaces, x)

进一步解析QT_ANNOTATE_CLASS,找到如下宏定义,

#ifndef QT_ANNOTATE_CLASS

# ifndef Q_COMPILER_VARIADIC_MACROS

define QT_ANNOTATE_CLASS(type, x)

# else

define QT_ANNOTATE_CLASS(type, ...)

# endif

#endif

这里可以看到只是一个空的定义,所以在源码中没有实际意义。主要用于MOC的输入,MOC会为Q_INTERFACES动态生成一些代码,确保qobject_cast()能正确进行QObject*到接口指针的转换,下面实例中详细讲述。

3. Q_PLUGIN_METADATA插件元数据宏

#define Q_PLUGIN_METADATA(x) QT_ANNOTATE_CLASS(qt_plugin_metadata, x)

与Q_INTERFACES类似,在代码层面也是空的,也用于MOC的输入,让MOC来动态生成一些代码。实际上,Q_PLUGIN_METADATA让MOC生成导出函数qt_plugin_instance(),供QPluginLoader()调用,创建接口实例,返回QObject的指针,在下面实例中详述。

4.MOC与Q_INTERFACES\Q_PLUG_METADATA的关系

Qt的插件机制是建立在元对象系统之上,所以要看一下Moc与Q_INTERFACES\Q_PLUGIN_METADATA两个宏之间的关系。

以OpenCVGrabber插件为例,

 

Q_PLUGIN_METADATA宏在自动生成的Moc文件中有IID与ClassName的信息,如下图,

 

查看一下,QT_MOC_EXPORT_PLUGIN的宏定义,

# define QT_MOC_EXPORT_PLUGIN(PLUGINCLASS, PLUGINCLASSNAME) \

            Q_EXTERN_C Q_DECL_EXPORT \

            const char *qt_plugin_query_metadata() \

            { return reinterpret_cast<const char *>(qt_pluginMetaData); } \

            Q_EXTERN_C Q_DECL_EXPORT QT_PREPEND_NAMESPACE(QObject) *qt_plugin_instance() \

            Q_PLUGIN_INSTANCE(PLUGINCLASS)

其中,Q_PLUGIN_INSTANCE,就是返回一个实例

#define Q_PLUGIN_INSTANCE(IMPLEMENTATION) \

        { \

            static QT_PREPEND_NAMESPACE(QPointer)<QT_PREPEND_NAMESPACE(QObject)> _instance; \

            if (!_instance) {    \

                QT_PLUGIN_RESOURCE_INIT \

                _instance = new IMPLEMENTATION; \

            } \

            return _instance; \

        }

Q_INTERFACES展开moc文件看到如下自动生成代码,

 

总结如下,

  1. Q_INTERFACES,确保能够正确类型转换;
  2. Q_PLUGIN_METADATA,生成插件元数据且生成qt_plugin_instance,供QPluginLoader使用;

5.QT插件加载器QPluginLoader

首先,看看它的声明比较简单

 

里面的instance返回对象实例指针,load()加载插件。上面声明中,有QJsonObject的定义来描述元数据,下面简单看一下元数据的描述格式Json

6. Json与插件元数据

Json是一种存储结构化数据的一种格式,概念中与xml类似,有6中基本数据类型:

Bool, double, string, array, object与null.

Json在插件中主要存储插件的元数据信息,在Qt中有一个专门的类QJsonObject对Json描述,与下表中其他配套的类一起来对Json管理。

类名

功能(中文)

QJsonArray

封装Json数组

QJsonDocument

读写Json文本

QJsonObject

封装Json对象

QJsonObject::iterator

Json迭代器

QJsonObject::const_iterator

Json常迭代器

QJsonParseError

报告Json解析错误

QJsonValue

封装Json值

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值