C++ 関数ポインタとクラス
-
09-06-2019 - |
質問
私が持っているとしましょう:
void Render(void(*Call)())
{
D3dDevice->BeginScene();
Call();
D3dDevice->EndScene();
D3dDevice->Present(0,0,0,0);
}
レンダリングに使用したい関数が関数または static
メンバー関数:
Render(MainMenuRender);
Render(MainMenu::Render);
ただし、ほとんどの場合、レンダリング関数はメンバー変数にアクセスする必要があり、クラスインスタンスをグローバルにしないほうがよいため、実際にはクラスメソッドも使用できるようにしたいと考えています。
Render(MainMenu->Render);
ただし、これを行う方法がまったくわかりませんが、依然として関数と static
使用するメンバー関数。
解決
この猫の皮を剥ぐ方法は、テンプレートを含めてたくさんあります。私のお気に入りは ブースト機能 長期的にはそれが最も柔軟性があることがわかったからです。こちらもお読みください ブーストバインド メンバー関数へのバインドや他の多くのトリックに使用できます。
次のようになります。
#include <boost/bind.hpp>
#include <boost/function.hpp>
void Render(boost::function0<void> Call)
{
// as before...
}
Render(boost::bind(&MainMenu::Render, myMainMenuInstance));
他のヒント
ラッパー関数も作れます void Wrap(T *t)
それはただ電話するだけです t->Call()
そして持っています Render
このような関数をオブジェクトと一緒に受け取ります。あれは:
void Wrap(T *t)
{
t->Call();
}
void Render(void (*f)(T *), T *t)
{
...
f(t);
...
}
何かについて C++ FAQ:メンバーへの指示 と言うのですか?
インスタンスへのポインタをメンバーとして受け入れるグローバル関数「Call」を定義することで、これを一度実行しました。
void CallRender(myclass *Instance)
{
Instance->Render();
}
したがって、レンダリングは次のようになります。
void Render(void (*Call)(myclass*), myclass* Instance)
{
...
Call(Instance);
...
}
そして、レンダリングの呼び出しは次のようになります。
Render(CallRender, &MainMenu);
それが醜いことはわかっていますが、私にとってはうまくいきました(私はpthreadsを使用していました)
オブジェクトへの参照も持っていない限り、ポインターからメンバー関数を呼び出すことはできません。例えば:
((object).*(ptrToMember))
したがって、レンダリング メソッドのシグネチャを変更しない限り、これを実現することはできません。 これ この記事では、これが一般的に悪い考えである理由を説明しています。
より良い方法は、レンダリング メソッドを持つクラスが実装できる「Renderer」インターフェイスを定義し、それをメインの Render メソッドのパラメータ タイプにすることです。次に、参照による静的メソッドの呼び出しをサポートする「StaticCaller」実装を作成できます。
例: (私の C++ は本当に錆びていて、これもコンパイルしていません)。
void Render(IRenderer *Renderer)
{
D3dDevice->BeginScene();
Renderer->Render();
D3dDevice->EndScene();
D3dDevice->Present(0,0,0,0);
}
// The "interface"
public class IRenderer
{
public:
virtual void Render();
};
public class StaticCaller: public IRenderer
{
void (*Call)();
public:
StaticCaller((*Call)())
{
this->Call = Call;
}
void Render()
{
Call();
}
};
これはすべて定型的なものですが、読みやすくなるはずです。
以下を使用して、クラス T のメンバー関数への関数ポインターを宣言できます。
typedef void (T::*FUNCTIONPOINTERTYPE)(args..)
FUNCTIONPOINTERTYPE function;
そしてそれを次のように呼び出します。
T* t;
FUNCTIONPOINTERTYPE function;
(t->*function)(args..);
これを、可変引数、型、戻り値などを備えた便利なカリー化システムに外挿するのは単調で面倒です。前述のブースト ライブラリについて良い評判を聞いたので、思い切った行動を起こす前にそれを検討することをお勧めします。