クラス内のメンバー関数を、メンバー関数クラスポインターを受け取る関数に渡そうとしています。私が抱えている問題は、thisポインターを使用してクラス内でこれを適切に行う方法がわからないことです。誰か提案はありますか?
次に、メンバー関数を渡すクラスのコピーを示します。
class testMenu : public MenuScreen{
public:
bool draw;
MenuButton<testMenu> x;
testMenu():MenuScreen("testMenu"){
x.SetButton(100,100,TEXT("buttonNormal.png"),TEXT("buttonHover.png"),TEXT("buttonPressed.png"),100,40,&this->test2);
draw = false;
}
void test2(){
draw = true;
}
};
関数x.SetButton(...)は、「オブジェクト」がテンプレートである別のクラスに含まれています。
void SetButton(int xPos, int yPos, LPCWSTR normalFilePath, LPCWSTR hoverFilePath, LPCWSTR pressedFilePath, int Width, int Height, void (object::*ButtonFunc)()) {
BUTTON::SetButton(xPos, yPos, normalFilePath, hoverFilePath, pressedFilePath, Width, Height);
this->ButtonFunc = &ButtonFunc;
}
誰かがこの関数を適切に送信して後で使用できるようにする方法についてアドバイスがあれば。
ポインターでメンバー関数を呼び出すには、2つのものが必要です。オブジェクトへのポインターと関数へのポインターです。 MenuButton::SetButton()
には両方が必要です
_template <class object>
void MenuButton::SetButton(int xPos, int yPos, LPCWSTR normalFilePath,
LPCWSTR hoverFilePath, LPCWSTR pressedFilePath,
int Width, int Height, object *ButtonObj, void (object::*ButtonFunc)())
{
BUTTON::SetButton(xPos, yPos, normalFilePath, hoverFilePath, pressedFilePath, Width, Height);
this->ButtonObj = ButtonObj;
this->ButtonFunc = ButtonFunc;
}
_
次に、両方のポインタを使用して関数を呼び出すことができます。
_((ButtonObj)->*(ButtonFunc))();
_
オブジェクトへのポインタをMenuButton::SetButton()
に渡すことを忘れないでください:
_testMenu::testMenu()
:MenuScreen("testMenu")
{
x.SetButton(100,100,TEXT("buttonNormal.png"), TEXT("buttonHover.png"),
TEXT("buttonPressed.png"), 100, 40, this, test2);
draw = false;
}
_
このような場合は、boost::bind
とboost::function
を強くお勧めします。
これはかなり古いトピックであることは知っています。しかし、c ++ 11でこれを処理するエレガントな方法があります
#include <functional>
このように関数ポインタを宣言します
typedef std::function<int(int,int) > Max;
このことを渡す関数を宣言します
void SetHandler(Max Handler);
通常の関数を渡すとすると、通常のように使用できます
SetHandler(&some function);
メンバー関数があるとします
class test{
public:
int GetMax(int a, int b);
...
}
あなたのコードでは、このようにstd::placeholders
を使用して渡すことができます
test t;
Max Handler = std::bind(&test::GetMax,&t,std::placeholders::_1,std::placeholders::_2);
some object.SetHandler(Handler);
標準オブジェクト指向を使用するほうがよいでしょうか。コントラクト(仮想クラス)を定義して独自のクラスに実装し、独自のクラスへの参照を渡して、レシーバーにコントラクト関数を呼び出させるだけです。
あなたの例を使用します(「test2」メソッドの名前を「buttonAction」に変更しました):
class ButtonContract
{
public:
virtual void buttonAction();
}
class testMenu : public MenuScreen, public virtual ButtonContract
{
public:
bool draw;
MenuButton<testMenu> x;
testMenu():MenuScreen("testMenu")
{
x.SetButton(100,100,TEXT("buttonNormal.png"),
TEXT("buttonHover.png"),
TEXT("buttonPressed.png"),
100, 40, &this);
draw = false;
}
//Implementation of the ButtonContract method!
void buttonAction()
{
draw = true;
}
};
レシーバーメソッドでは、ButtonContractへの参照を保存し、ボタンのアクションを実行する場合は、保存されているButtonContractオブジェクトの 'buttonAction'メソッドを呼び出します。
他の人はそれを正しく行う方法をあなたに話しました。しかし、このコードが実際に危険であると誰もあなたに言っていないことに驚いています:
_this->ButtonFunc = &ButtonFunc;
_
ButtonFuncはパラメーターであるため、関数が戻るとスコープ外になります。あなたはそのアドレスを取っています。タイプvoid (object::**ButtonFunc)()
(メンバー関数へのポインターへのポインター)の値を取得して、this-> ButtonFuncに割り当てます。当時、これを使用しようとすると、> ButtonFuncは(現在はもう存在しない)ローカルパラメータのストレージにアクセスしようとし、プログラムはおそらくクラッシュします。
私はコモドアのソリューションに同意します。しかし、あなたは彼のラインをに変更する必要があります
_((ButtonObj)->*(ButtonFunc))();
_
buttonObjはオブジェクトへのpointerであるためです。
まれにBorland C++ Builderで開発していて、その開発環境に固有のコード(つまり、他のC++コンパイラーでは機能しないコード)を作成しても構わない場合は、__ closureキーワードを使用できます。 。 C++ Builderクロージャーに関する小さな記事 を見つけました。これらは主にBorland VCLでの使用を目的としています。