1. 程式人生 > >Qt5的插件機制(6)--開發Qt插件時幾個重要的宏

Qt5的插件機制(6)--開發Qt插件時幾個重要的宏

nor article pre strcmp object ant a plugin 通過 public


怎樣開發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)); } \    
                    // qt_metacast通過插件的IID來映射接口類的指針。一個IID綁定一個接口類
    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 FILE "MyPlugin.json")
    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)    // Q_DECLARE_INTERFACE宏就是利用這個函數實現的qobject_cast類型映射
{
    if (!_clname) return 0;
    if (!strcmp(_clname, qt_meta_stringdata_MyPlugin.stringdata))    // 假設_clname與類的名稱MyPlugin匹配,返回有效指針
        return static_cast<void*>(const_cast< MyPlugin*>(this));
    if (!strcmp(_clname, "MyPluginInterface"))        // 假設_clname與接口類的名稱MyPluginInterface匹配,返回有效指針
        return static_cast< MyPluginInterface*>(const_cast< MyPlugin*>(this));
    if (!strcmp(_clname, "org.qt-project.Qt.PluginDemo"))    // 假設_clname與接口類的IID匹配,返回有效指針。
                                // 這裏就用到了調用Q_DECLARE_INTERFACE宏時使用的IID參數
                                // 並且,Q_DECLARE_INTERFACE宏的代碼中也是利用IID映射實現的qobject_cast
        return static_cast< MyPluginInterface*>(const_cast< MyPlugin*>(this));
    return QObject::qt_metacast(_clname);
}
    ...
    ...




Qt5的插件機制(6)--開發Qt插件時幾個重要的宏