私は非常に静的な環境でプログラミングを行っており、問題/コードを可能な限り最善の方法で一般化し、クリーンにしてボイラープレート コードを回避したいと考えています。これは私の場合です。プログラムと拡張機能の間に位置する変更システムを開発しています。拡張機能は API 呼び出しを転送します。変更内容がプログラムによって読み込まれると、関数ポインターだけで構成されるテーブルへのポインターを受け取ります。
struct APITable
{
void (*MouseClick)(int, int);
void (*MouseLeave)(bool);
int (*MouseRet)(float, int);
// And about a 200 more
// ......
};
この関数では、コールバック関数/ポインターを自分自身 (つまりapiTable->MouseClick = &MyMouseClick;
) を指すように設定します。複数のプラグインをサポートするために、このフレームワークを拡張しようとしています (一度に 1 つの変更しか許可されないため)。これは、追加のプラグインを (ライブラリとして) ロードし、ロードされたプラグインにすべてのコールバック ( など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
、1 つはvoid
関数用で、もう 1 つは戻り値を持つ関数用です。これはうまくいきますが、別の解決策を選ぶことは間違いありません (C++ は静的に型付けされた言語であるため、これは不可能かもしれません)。
ポイントは; 定型コードを避けて、クリーンで効率的な方法でこの手順を一般化したいと考えています。言及する価値があるのは、void として宣言されていないコールバックで、関数が元の関数の戻り値をオーバーライドする可能性があることです。
したがって、それを骨に剥がすには:Program->MyExtension->Plugins&Engine
注: C++ 以外の言語は使用したくありません。必要に応じて C++11 の機能を使用します。
編集:興味がある場合、これは私の変更がプログラムによってロードされる方法です:
extern "C" ModLoad(APITable * apiTable)
{
apiTable->MouseClick = &MyMouseClick;
apiTable->MouseLeave = &MyMouseLeave;
// And so on
// ...
}