我在一个非常静态的环境中编程,并希望以最好的方式概括问题/代码,使其干净并避免任何样板代码。这是我的情况;我正在开发一个位于程序和扩展之间的修改系统,其中扩展将被转发 API 调用。当我的修改被程序加载时,我收到一个指向完全由函数指针组成的表的指针。
struct APITable
{
void (*MouseClick)(int, int);
void (*MouseLeave)(bool);
int (*MouseRet)(float, int);
// And about a 200 more
// ......
};
在这个函数中,我将回调函数/指针设置为指向我自己的(即apiTable->MouseClick = &MyMouseClick;
)。我正在尝试扩展这个框架(因为它一次只允许一个修改)以支持多个插件。这是通过加载额外的插件(作为库)然后将所有回调(例如MouseClick
)转发到加载的插件来完成的。这是一个例子;
void MyMouseClick(int x, int y)
{
bool blockOriginal = false;
// Iterate over all plugins
if(plugin_function_is_defined_pre)
blockOriginal = call_plugin_callback_pre(x, y);
if(!blockOriginal)
EngineMouseClick(x, y); // This is the programs "engine" function, which I have to call if I want normal execution flow
// Iterate over all plugins
if(plugin_function_is_defined_post)
call_plugin_callback_post(x, y);
}
这是一个非常简化的程序,但我认为它说明了需要说明的一切。因为我有超过 200 个函数,所以我无法复制和粘贴所有这些样板代码。正常的过程可能是一个#define
,一个用于void
函数,一个用于具有返回值的函数。虽然这可行,但我肯定更喜欢另一种解决方案(这可能是不可能的,因为 C++ 是一种静态类型的语言)。
重点是; 我想以一种简洁有效的方式概括这个过程,避免任何样板代码。值得一提的是,在未声明为 void 的回调中,函数可能会覆盖原始函数的返回值。
所以要把它剥到骨头上:Program->MyExtension->Plugins&Engine
注意:我不想使用除 C++ 之外的任何语言,如有必要,我将使用 C++11 功能!
编辑:如果有兴趣,这就是我的修改被程序加载的方式:
extern "C" ModLoad(APITable * apiTable)
{
apiTable->MouseClick = &MyMouseClick;
apiTable->MouseLeave = &MyMouseLeave;
// And so on
// ...
}