现在的位置: 首页 > 综合 > 正文

Qt plugin系统的几点说明

2013年03月12日 ⁄ 综合 ⁄ 共 1922字 ⁄ 字号 评论关闭

对于一个大型软件系统来说,实现plugin是一件很美妙的事情,一个成功的plugin系统可以使软件增色不少。Plugin最大的功能是在一定程度内提高了软件的灵活度和可扩展性。一个设计精良的server软件plugin系统甚至在server程序不退出的情况下可以调用新加入的plugin,实现不间断服务的升级。那么,Qt是怎样实现它的plugin系统呢?

使用Qt创建plugin和在程序中调用plugin是很简单的事情,Qt提供了很多helper class供大家使用。总体来说,Qtplugin分为2种,按照Qt文档的说法,一种是高等级的plugin。其实说白了就是已经确定interfaceQt本身的plugin。(大家可能都知道,Qt的很多功能,像数据库驱动、图片格式支持、文字内码等都是通过plugin实现的)举个例子来说,Qt可能本身没有西班牙语(希望这次西班牙夺冠:-)的文字内码,但是程序员可以通过按照codec interface写出西班牙语的codec plugin从而使Qt支持西班牙语。

另一种是低等级的plugin。就是该plugininterface也需要程序员自己编写。所以如果你知道怎么写一个低等级的plugin并使用它之后,高等级的plugin也就完全掌握了。下面我就重点说说低等级的pluginQt里实现的一些要点。

从编程的角度,重点还是OOP。所谓的plugin,其实就是一些按照特定interface写成的子类。该Interface必须是虚基类,且所有函数(除了析构)都是虚函数。而所谓的plugin就是继承该虚基类和QObject的子类。当程序调用该plugin的某个函数时,是通过该plugin的虚基类在运行时动态绑定至子类的vtable执行的。所以Qt实现plugin的基础还是OOP的继承和多态。

举个大家都知道的例子来说明,PhotoShop(可能它并不是这么实现的)的所有滤镜有个统一的interface虚基类,该类提供了一个虚函数doSomeWork用于实现滤镜效果。当用户选择某个特殊滤镜时,程序会调用plugin中该滤镜classdoSomeWork实现函数来执行该操作,从而实现特定的滤镜功能。

那么为什么该plugin类不但要继承interface类,还需要继承QObject类呢?原因是调用plugin时需要该pluginQObject那部分的meta信息。如果大家看过例子代码,会发现,用QPluginLoader调用plugin的文件后,关键的一步是确定该plugin是什么类型的。简单的另人惊讶,一句qobject_cast就搞定了。刚看到这句我百思不得其解,好在Qt有源代码可看,看了源代码发现qobject_cast类似于标准C++dynamic_cast,且无需RTTI支持并能跨DLL。在代码中,qobject_cast是通过QObjectmetaobjectcast函数来实现的。那么该函数是怎么写的呢?

/*!

    /internal

    Returns /a obj if object /a obj inherits from this

    meta-object; otherwise returns 0.

*/

QObject *QMetaObject::cast(QObject *obj) const

{

    if (obj) {

        const QMetaObject *m = obj->metaObject();

        do {

            if (m == this)

                return const_cast<QObject*>(obj);

        } while ((m = m->d.superdata));

    }

    return 0;

}

从子类的metaobject开始查找,一直向父类循环,直至找到一致的meta(类信息)。所以,qobject_cast其实是确定该类是否是指定父类的派生类,如果是的话得到其指针。也就是说确定一个plugin是什么类型是通过继承关系来实现的。

从文件的角度来说,一个或多个plugin可以生存在同一个动态库里,windows下是dll。那么,这个dll怎么能动态的将plugin暴露给调用者呢?最关键的是Q_EXPORT_PLUGIN2这个宏。Qt文档特意说明,同一个plugin必须且只能调用它一次,且必须在实现文件的末尾。为什么呢?

因为这个宏最终调用了另一个宏,Q_PLUGIN_INSTANCE,而它的定义如下:

#define Q_PLUGIN_INSTANCE(IMPLEMENTATION) /

        { /

-->

作者:

抱歉!评论已关闭.