前面几片文章中提到的类,包括 QxxxFactory、QFactoryLoader、QLibraryPrivate 等, 都是Qt的内部类,不是Qt的标准API,如果要在应用程序的层次上加载库或插件,则需要借助另外两个类,QLibrary 和 QPluginLoader,这两个类属于Qt的标准API,可以在普通Qt应用程序的开发中使用。
这两个类的用法比较简单,可以在 Qt Assistant中直接找到关于他们的用法介绍,如果看了前面介绍QLibrayPrivate类的那篇文章,
这两个类学起来就更简单了。所以本文不对这两个类做过多介绍,只提纲挈领的说几点。
首先这两个类,前面的文章也提到过,他们的私有数据类都是QLibrayPrivate,所以他们实现的功能基本都是基于QLibrayPrivate这个类的。
拿QLibrary类说,可以用库的文件名来构造这个类的对象,它的 load() 方法可用于加载它绑定的库,unload() 则用于卸载库,
resolve() 方面用于实例化库中符号,这三个方法的内部都是通过调用 QLibrayPrivate类的几个同名方法实现的。
对于QPluginLoader类,它与QLibrary类显著的区别是多了一个 instance() 方法,能直接从库(插件)中获得插件的实例。
开发Qt插件时几个重要的宏
如何开发Qt插件,可以在Qt Assistant 中搜索"Qt Plugins"或"How to Create Qt Plugins",看看那篇manual中的介绍。
其中涉及到了几个宏
Q_DECLARE_INTERFACE( ClassName, Identifier)
This macro associates the given Identifier (a string literal) to the interface class called ClassName. The Identifier must be unique.
This macro is normally used right after the class definition for ClassName, in a header file.
Q_INTERFACES(...)
This macro tells Qt which interfaces the class implements. This is used when implementing plugins.
Q_PLUGIN_METADATA(...)
This macro is being used to declare meta data that is part of a plugin that instantiates this object.
The macro needs to declare the IID of the interface implemented through the object, and reference a file containing the meta data for the plugin.
There should be exactly one occurrence of this macro in the source code for a Qt plugin.
其中,Q_PLUGIN_METADATA(...)宏在前面讲“Qt插件的元信息”的那篇文章中已经介绍过了,它基本是这些宏里最重要的一个,因为
MOC会根据这个宏生成很多跟该插件相关的东西,包括元信息、获取插件实例的函数等。可用它可以将插件导出,其作用类似于老版本
Qt中的 Q_EXPORT_PLUGIN2 宏
Q_DECLARE_INTERFACE 宏是与qobject_cast相关的,它为接口类定义了qobject_interface_iid和qobject_cast这两个模板
Qt的源码中给出了宏Q_DECLARE_INTERFACE的定义
- # 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) : 0)); } \
-
- template <> inline IFace *qobject_cast<IFace *>(const QObject *object) \
- { return reinterpret_cast<IFace *>((object ? const_cast<QObject *>(object)->qt_metacast(IId) : 0)); }
Q_INTERFACES宏也是与qobject_cast相关,没有Q_DECLARE_INTERFACE和Q_INTERFACES这两个宏,就无法对从插件中获取的实例指针进行qobject_cast映射。
不过,Q_INTERFACES宏并没有在Qt的源码中定义,他是MOC的菜,MOC会利用这个宏生成一些代码。要注意一点,如果一个头文件或源文件中用到了Q_INTERFACES宏,
那么在调用这个宏之前,必须存在一个 Q_DECLARE_INTERFACE宏声明相应的接口(或者包含一个用Q_DECLARE_INTERFACE宏声明了该接口的头文件),MOC会检查这一点,因为它在为Q_INTERFACES宏生成代码时要用到Q_DECLARE_INTERFACE宏的IID参数。
举例,
头文件 MyPluginInterface.h 中虚拟接口类的定义如下
- #include <QtPlugin>
- #define QtPluginDemo_iid "org.qt-project.Qt.PluginDemo" // 定义接口的IID
- class MyPluginInterface
- {
- public:
- virtual ~MyPluginInterface(){}
- virtual void showPluginName();
- };
- Q_DECLARE_INTERFACE ( MyPluginInterface, QtPluginDemo_iid ) ;
头文件MyPlugin.h中类的定义如下
- class MyPlugin : public QObject, public MyPluginInterface
- {
- Q_OBJECT
-
- Q_PLUGIN_METADATA ( IID QtPluginDemo_iid)
- Q_INTERFACES(MyPluginInterface)
-
- public:
- void showPluginName();
- };
将头文件MyPlugin.h用MOC处理之后,生成的代码中有如下部分
(只列出了MOC为Q_INTERFACES宏生成的代码,MOC为Q_PLUGIN_METADATA宏生成的代码在前面讲“Qt插件的元信息”的那篇文章中介绍过了):
- ...
- ...
-
- static const qt_meta_stringdata_MyPlugin_t qt_meta_stringdata_MyPlugin = {
- {
- QT_MOC_LITERAL(0, 0, 8)
- },
- "MyPlugin"
- };
- ...
- ...
-
- void *MyPlugin::qt_metacast(const char *_clname)
- {
- if (!_clname) return 0;
- if (!strcmp(_clname, qt_meta_stringdata_MyPlugin.stringdata))
- return static_cast<void*>(const_cast< MyPlugin*>(this));
- if (!strcmp(_clname, "MyPluginInterface"))
- return static_cast< MyPluginInterface*>(const_cast< MyPlugin*>(this));
- if (!strcmp(_clname, "org.qt-project.Qt.PluginDemo"))
-
-
- return static_cast< MyPluginInterface*>(const_cast< MyPlugin*>(this));
- return QObject::qt_metacast(_clname);
- }
- ...
- ...