撰写插件
撰写插件意味着什么?插件框架是非常generic,并且不提供任何可以与你的应用交互的切实的对象。你必须在插件框架上构建你自己的应用程序模型。这意味着你的应用程序(加载插件)以及插件自身必须同意并通过某种模型来协作。通常这表明应用程序期待插件提供暴露某种特定API的某种类型的对象。插件框架将提供注册、枚举及加载这些对象的基础设施。示例1是一个叫做IActor的C++接口的定义。它有两个操作——getInitialInfo()和play()。注意该接口不是充分的,因为getInitialInfo()期望一个指向名为ActorInfo的结构体的指针,且play()期望一个指向另一个叫做ITurn接口的指针。这是实际的一个案例,你必须设计并指定整个对象模型。
struct IActor
{
virtual ~IActor() {}
virtual void getInitialInfo(ActorInfo * info) = 0;
virtual void play( ITurn * turnInfo) = 0;
};
示例1
每个插件可以注册多个实现了IActor接口的类型。当应用程序决定示例化一个由插件注册的对象,它将调用注册的,由插件实现的PF_CreateFunc函数。插件负责创建一个合适的对象并将其返回给应用程序。返回类型指定为void *是因为对象创建操作是通用插件框架的一部分,该部分不知道任何关于特定IActor接口的信息。应用程序随后将void *转换到IActor *,然后就可以在整个接口中使用它,好像它是一个正常的对象。当应用程序使用完IActor对象后,它执行注册的由插件实现的PF_DestroyFunc函数,然后插件销毁actor对象。目前不好考虑虚拟的析构函数,我会在后面的部分讨论它。
编程语言支持
在二进制兼容性部分我解释了你可以利用C++的vtable一级的兼容性,如果你的编译器满足的话。你也可以使用C一级的兼容性,这样你就可以使用不同的编译器来构建应用程序和插件,但你将被局限在C的交互上。你的应用程序对象模型必须是基于C的。你不能使用好的C++接口如IACTOR,但你必须设计一个相似的C接口。
纯C
在纯C的编程模型中你只需要用C开发插件。当你实现PF_CreateFunc函数时你返回一个在你的应用程序C对象模型中与其它C对象交互的C对象。所有的话题都是关于C对象和C对象模型的。所有人都知道C是一个过程语言,没有对象的概念。然而C提供了足够的抽象机制来实现对象以及多态(在此处是必须的)并支持面向对象的编程泛型。实际上,最初的C++编译器是一个C编译器的事实上的一个前端(front-end)。它根据C++代码产生C代码,然后使用一个普通的C编译器来编译该C代码。它的名字Cfront说明了一切。
使用包含函数指针的结构体(译注:就可以获得OO特性)。每个函数的签名应当接受它所属结构体作为第一个参数该结构体也可以包含其它的数据成员。这样提供了(与C++类有关的简单的土语)如:封装(状态和行为捆绑)、继承(通过将基结构体的对象作为第一个数据成员)以及多态(通过设置不同的函数指针。)(译注:没错,这就是用C来编写OO程序的基本要求和方法,我也用C写过OO程序)。
C不支持析构函数、函数及操作符重载,名字空间,因此你定义接口时只有很少的选项。这也许是“塞翁失马,焉知非福”,因为接口应该被可能掌握C++另一个子集的其它人所使用。减少语言的范围可能会提升你的接口的简单性和可用性。
我将在插件框架的后续文章中探究OO的C。列表2包含了陪伴该文章系列(仅仅是投你所好)的示例游戏的C对象模型。如果你快速浏览一下你会看见它甚至支持集合以及遍历。
#ifndef C_OBJECT_MODEL
#define C_OBJECT_MODEL
#include
#define MAX_STR 64 /* max string length of string fields */
typedef struct C_ActorInfo_
{
apr_uint32_t id;
apr_byte_t name[MAX_STR];
apr_uint32_t location_x;
apr_uint32_t location_y;
apr_uint32_t health;
apr_uint32_t attack;
apr_uint32_t defense;
apr_uint32_t damage;
apr_uint32_t movement;
} C_ActorInfo;
typedef struct C_ActorInfoIteratorHandle_ { char c; } * C_ActorInfoIteratorHandle;
typedef struct C_ActorInfoIterator_
{
void (*reset)(C_ActorInfoIteratorHandle handle);
C_ActorInfo * (*next)(C_ActorInfoIteratorHandle handle);
C_ActorInfoIteratorHandle handle;
} C_ActorInfoIterator;
typedef struct C_TurnHandle_ { char c; } * C_TurnHandle;
typedef struct C_Turn_
{
C_ActorInfo * (*getSelfInfo)(C_TurnHandle handle);
C_ActorInfoIterator * (*getFriends)(C_TurnHandle handle);
C_ActorInfoIterator * (*getFoes)(C_TurnHandle handle);
void (*move)(C_TurnHandle handle, apr_uint32_t x, apr_uint32_t y);
void (*attack)(C_TurnHandle handle, apr_uint32_t id);
C_TurnHandle handle;
} C_Turn;
typedef struct C_ActorHandle_ { char c; } * C_ActorHandle;
typedef struct C_Actor_
{
void (*getInitialInfo)(C_ActorHandle handle, C_ActorInfo * info);
void (*play)(C_ActorHandle handle, C_Turn * turn);
C_ActorHandle handle;
} C_Actor;
#endif
列表2
纯C++