Qt 4 插件开发(2)

插件系统分成两个主要部分:插件加载器和插件。为简单起见,我们将整个应用程序设计为一个插件加载器。下面,我们将给出一个实例,来阐述如何在 Qt 4 中开发应用程序插件。

我们的例子很简单:这是一个类似游戏的系统,由插件提供游戏中出现的各种怪物(类似于我们前面设计插件框架时所提供的程序)。游戏启动时,将这些插件加载到系统中,并与主程序进行交互。我们将从最简单的情形开始着手,一步步丰富我们的游戏示例。

插件与主程序应当有一种约定。通过这种约定,主程序知道插件提供了哪些功能。也就是说,插件不是随意编写的,而是应该应该满足一些接口。主程序通过这些接口与插件交互,无需知道插件本身具体是如何实现这些接口,只需知道,插件的确实现了这些接口。这也就是基于接口编程的优势之一。

下面,我们就先建立一个最简单的工程作为主程序,名字就叫作 GameSystem,其 pro 文件如下所示:

QT       += core
QT       -= gui

TARGET    = GameSystem
CONFIG   += console

TEMPLATE = app

DESTDIR = ..

MOC_DIR     = sys
OBJECTS_DIR = sys

SOURCES += main.cpp

HEADERS += \
    monsterinterface.h

我们可以在 Qt Creator 中新建工程。不过,如果你使用 Qt Creator 这里 IDE,需要注意的是,将 Project 的 Build Directory 设置一下。比如豆子设置为 E:\Qt\game\build\sys。注意,我们为简单起见,使用的是 Qt 命令行工程,没有添加 GUI 部分,因此我们的 .pro 文件中有这么一行:QT -= gui。

main.cpp 使用默认的:

#include <QtCore>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    return app.exec();
}

下面是 monsterinterface.h 的代码,这就是我们前面所说的插件都需要实现的这个约定(接口):

#ifndef MONSTER_H
#define MONSTER_H

#include <QtPlugin>
#include <QString>

class MonsterInterface
{
public:
    virtual ~MonsterInterface() {}

    virtual QString name() const = 0;
};

Q_DECLARE_INTERFACE(MonsterInterface,"org.galaxyworld.plugins.MonsterInterface/1.0")

#endif // MONSTER_H

这个接口值得我们说明一下。首先,C++ 没有类似 Java 或者 C# 的专门的 interface,因此,我们使用的是 class 来模拟接口。这样做的要求是,接口应当有一个 virtual 的析构函数,以便实现了接口的子类在析构的时候能够自动调用父类的析构函数,从而避免内存泄露。第二,接口中所有的函数都应当是纯虚函数,也就是 virtual 的并且要有 = 0。这是 C++ 的要求,与 Qt 无关。最后,注意,文件末尾处有一个Q_DECLARE_INTERFACE宏,用于告诉 Qt 的元数据系统 metadata system,这是一个接口。这个宏有两个参数,第一个是接口类的名字,这里就是 MonsterInterface;第二个是接口的标识符,是一个唯一的字符串,为保证唯一性,通常采取域名倒写的形式,最后用 / 分隔开版本号(关于域名倒写,可以参考 Java package 的命名规范,简而言之,就是把你的域名倒过来书写)。这样,我们就完成了接口的编写。

我们的接口很简单,出去虚析构函数,只有一个函数是子类必须实现的:QString name() const。顾名思义,也就是返回这个插件的名字。当然,在真正使用的系统中,这个接口可能相当复杂,并且像 name 或者 version 这种属性,一般不大会放在代码中,而是在配置文件中(特别是版本号这种经常会修改的常量)。

现在,你可以编译一下这个工程。显然,你不会得到任何有意义的东西———仅仅是能够测试你的配置是否正确,代码是否能通过编译。编译之后,如果使用了影子构建,你应该在于 GameSystem 文件夹平级处得到一个 build 文件夹,里面就是我们编译出的 GameSystem.exe (Windows)。

下一节,我们将继续介绍如何基于这个 MonsterInterface 开发一个可以使用的插件。

Leave a Reply