Frage

Ich versuche, eine Member-Funktion innerhalb einer Klasse auf eine Funktion zu übergeben, die eine Elementfunktion der Klasse Zeiger nimmt. Das Problem, das ich habe, ist, dass ich nicht sicher bin, wie man richtig dies die diesen Zeiger unter Verwendung innerhalb der Klasse zu tun. Hat jemand Vorschläge?

Hier ist eine Kopie der Klasse, die die Member-Funktion ist vorbei:

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;
}
};

Die Funktion x.SetButton (...) in einer anderen Klasse enthalten ist, in der "Objekt" ist eine Vorlage.

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;
}

Wenn jemand irgendwelche Ratschläge, wie ich diese Funktion richtig senden, damit ich sie später verwenden kann.

War es hilfreich?

Lösung

Um eine Elementfunktion durch Zeiger aufrufen, müssen Sie zwei Dinge: Ein Zeiger auf das Objekt und einen Zeiger auf die Funktion. Sie müssen sowohl in 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;
}

Dann können Sie die Funktion mit beiden Zeiger aufrufen:

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

Vergessen Sie nicht, den Zeiger auf das Objekt zu MenuButton::SetButton() weitergeben müssen:

testMenu::testMenu()
  :MenuScreen("testMenu")
{
  x.SetButton(100,100,TEXT("buttonNormal.png"), TEXT("buttonHover.png"),
        TEXT("buttonPressed.png"), 100, 40, this, test2);
  draw = false;
}

Andere Tipps

Ich würde dringend empfehlen boost::bind und boost::function für so etwas.

Siehe Pass und eine Memberfunktion aufrufen (boost :: bind / boost :: Funktion?)

Ich weiß, dass dies ein ganz altes Thema ist. Aber es ist ein eleganter Weg, dies mit c zu handhaben ++ 11

#include <functional>

erklären, um Ihre Funktionszeiger wie folgt

typedef std::function<int(int,int) > Max;

erklären sich die Funktion Ihren Pass dieses Ding in

void SetHandler(Max Handler);

Angenommen, Sie eine normale Funktion es passieren können Sie es wie normale verwenden

SetHandler(&some function);

Angenommen, Sie eine Memberfunktion haben

class test{
public:
  int GetMax(int a, int b);
...
}

in Ihrem Code können Sie es passieren std::placeholders wie dies mit

test t;
Max Handler = std::bind(&test::GetMax,&t,std::placeholders::_1,std::placeholders::_2);
some object.SetHandler(Handler);

Möchten Sie nicht besser gedient Standard OO zu verwenden. Definieren Sie einen Vertrag (virtuelle Klasse) und implementieren, die in Ihrer eigenen Klasse, dann übergeben Sie einfach einen Verweis auf Ihre eigene Klasse und lassen Sie den Empfänger rufen Sie die Funktion Vertrag.

Mit Ihrem Beispiel (Ich habe die 'test2' Methode 'buttonAction' umbenannt):

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;
    }
};

Im Empfänger Methode speichern Sie die Referenz auf ein ButtonContract, dann, wenn Sie ausführen möchten rufen Sie die Schaltfläche Aktion nur die ‚buttonAction‘ Methode des gespeicherten ButtonContract Objekt.

In dem seltenen Fall, dass Sie mit Borland C ++ Builder Entwicklung werden passieren und nichts dagegen haben, das Schreiben von Code spezifisch für diese Entwicklungsumgebung (das heißt, Code, der nicht mit anderen C ++ Compiler funktionieren wird), können Sie das __closure Schlüsselwort. Ich fand einen kleine Artikel über C ++ Builder Schließungen . Sie sind mit Borland VCL in erster Linie für den Einsatz bestimmt ist.

Andere haben gesagt, wie man es richtig tun. Aber ich bin überrascht, niemand gesagt, dieser Code ist tatsächlich gefährlich:

this->ButtonFunc = &ButtonFunc;

Da ButtonFunc ein Parameter ist, wird es außerhalb des Gültigkeitsbereichs gehen, wenn die Funktion zurückkehrt. Sie nehmen ihre Adresse. Sie werden einen Wert vom Typ void (object::**ButtonFunc)() ( Zeiger auf einen Zeiger auf eine Elementfunktion ) erhalten und weist es this-> ButtonFunc. Zu der Zeit, würden Sie versuchen this- verwenden> ButtonFunc würden Sie versuchen, die Speicherung der (jetzt nicht mehr vorhandenen) lokalen Parameter zuzugreifen, und das Programm würde wahrscheinlich zum Absturz bringen.

Ich bin mit Commodore-Lösung. Aber man muss seine Linie ändern

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

da ButtonObj ist ein Zeiger zu widersprechen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top