27

クラス内のメンバー関数を、メンバー関数クラス ポインターを受け取る関数に渡そうとしています。私が抱えている問題は、 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;
}

後で使用できるように、この関数を適切に送信する方法についてアドバイスがあれば。

4

6 に答える 6

33

メンバー関数をポインターで呼び出すには、オブジェクトへのポインターと関数へのポインターの 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;
}
于 2008-09-24T23:11:53.577 に答える
15

このようなものには強くお勧めboost::bindboost::functionます。

メンバー関数の受け渡しと呼び出しを参照してください(boost::bind / boost::function?)

于 2008-09-24T22:46:47.397 に答える
5

標準のOOを使用する方が良いと思いませんか。コントラクト(仮想クラス)を定義し、それを独自のクラスに実装してから、独自のクラスへの参照を渡して、受信者にコントラクト関数を呼び出させます。

あなたの例を使用すると(「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」メソッドを呼び出すだけです。

于 2008-09-25T08:11:18.803 に答える
2

他の人はそれを正しく行う方法を教えてくれました。しかし、このコードが実際に危険であると誰も言わなかったことに驚いています。

this->ButtonFunc = &ButtonFunc;

ButtonFunc はパラメーターなので、関数が戻ると範囲外になります。あなたはそのアドレスを取得しています。タイプvoid (object::**ButtonFunc)()(メンバー関数へのポインターへのポインター) の値を取得し、それを this->ButtonFunc に割り当てます。this->ButtonFunc を使用しようとすると、(現在はもう存在しない) ローカル パラメーターのストレージにアクセスしようとすると、プログラムがクラッシュする可能性があります。

私はコモドールの解決策に同意します。しかし、あなたは彼の行をに変更する必要があります

((ButtonObj)->*(ButtonFunc))();

ButtonObj はオブジェクトへのポインタであるためです。

于 2008-11-23T16:58:18.937 に答える
2

たまたま Borland C++Builder で開発していて、その開発環境に固有のコード (つまり、他の C++ コンパイラでは動作しないコード) を書いてもかまわないというまれなケースでは、__closure キーワードを使用できます。 . C++Builder のクロージャに関する小さな記事を見つけました。これらは、主に Borland VCL で使用するためのものです。

于 2008-09-24T23:10:23.237 に答える