Ich versuche, eine Member-Funktion innerhalb einer Klasse an eine Funktion zu übergeben, die einen Member-Funktions-Klassenzeiger übernimmt. Das Problem, das ich habe, ist, dass ich nicht sicher bin, wie ich dies innerhalb der Klasse mit dem this-Zeiger richtig machen soll. Hat jemand Vorschläge?
Hier ist eine Kopie der Klasse, die die Member-Funktion übergibt:
Die Funktion x.SetButton(…) ist in einer anderen Klasse enthalten, wobei “object” ein Template ist.
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 einen Rat hat, wie ich diese Funktion richtig senden kann, damit ich sie später verwenden kann.
Commodore Jäger
Um eine Elementfunktion per Zeiger aufzurufen, benötigen Sie zwei Dinge: Einen Zeiger auf das Objekt und einen Zeiger auf die Funktion. Du brauchst beides drin MenuButton::SetButton()
A pointer to the class – soll das sein A pointer to the object?
– Vorac
12. November 2014 um 15:06 Uhr
Vielen Dank. Konnte nicht herausfinden, dass die Syntax so etwas wie ((ButtonObj)->*(ButtonFunc))() ist
– Nathanesau
3. Juni 2016 um 16:22 Uhr
Matt Cruikshank
Ich würde es dringend empfehlen boost::bind und boost::function für sowas.
Siehe Übergeben und Aufrufen einer Member-Funktion (boost::bind / boost::function?)
Yuanlong Li
Ich weiß, das ist ein ziemlich altes Thema. Aber es gibt einen eleganten Weg, dies mit c++11 zu handhaben
#include <functional>
Deklarieren Sie Ihren Funktionszeiger so
typedef std::function<int(int,int) > Max;
Deklarieren Sie die Funktion, in die Sie dieses Ding übergeben
void SetHandler(Max Handler);
Angenommen, Sie übergeben ihm eine normale Funktion, dann können Sie es wie gewohnt verwenden
SetHandler(&some function);
Angenommen, Sie haben eine Member-Funktion
class test{
public:
int GetMax(int a, int b);
...
}
In Ihrem Code können Sie es mit übergeben std::placeholders so was
test t;
Max Handler = std::bind(&test::GetMax,&t,std::placeholders::_1,std::placeholders::_2);
some object.SetHandler(Handler);
Danke dafür. Sie haben jedoch einen Typ: es ist std::placeholdersPlural.
– Artfunkel
26. Januar 2017 um 12:10 Uhr
Wären Sie nicht besser bedient, um Standard-OO zu verwenden. Definieren Sie einen Vertrag (virtuelle Klasse) und implementieren Sie diesen in Ihrer eigenen Klasse, übergeben Sie dann einfach eine Referenz an Ihre eigene Klasse und lassen Sie den Empfänger die Vertragsfunktion aufrufen.
Anhand Ihres Beispiels (ich habe die Methode ‚test2‘ in ‚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;
}
};
In der Empfängermethode speichern Sie den Verweis auf einen ButtonContract. Wenn Sie dann die Aktion der Schaltfläche ausführen möchten, rufen Sie einfach die ‘buttonAction’-Methode dieses gespeicherten ButtonContract-Objekts auf.
In dem seltenen Fall, dass Sie zufällig mit Borland C++Builder entwickeln und nichts dagegen haben, für diese Entwicklungsumgebung spezifischen Code zu schreiben (d. h. Code, der nicht mit anderen C++-Compilern funktioniert), können Sie das Schlüsselwort __closure verwenden . Ich habe einen … gefunden kleiner Artikel über C++Builder Closures. Sie sind hauptsächlich für die Verwendung mit Borland VCL vorgesehen.
Das ist eine ziemlich … obskure Lösung.
– Josh Matthews
25. September 2008 um 4:17 Uhr
Ja, es ist undurchsichtig. 🙂 Es gibt jedoch noch Delphi- und C++Builder-Legacy-Code im Firmenland. Am besten gründlich.
– Parappa
15. Oktober 2008 um 23:26 Uhr
Johannes Schaub – litb
Andere haben dir gesagt, wie man es richtig macht. Aber ich bin überrascht, dass Ihnen niemand gesagt hat, dass dieser Code tatsächlich gefährlich ist:
this->ButtonFunc = &ButtonFunc;
Da ButtonFunc ein Parameter ist, verlässt er den Geltungsbereich, wenn die Funktion zurückkehrt. Sie nehmen seine Adresse. Sie erhalten einen Wert vom Typ void (object::**ButtonFunc)() (Zeiger auf einen Zeiger auf eine Member-Funktion) und weist es diesem zu->ButtonFunc. Wenn Sie versuchen würden, this->ButtonFunc zu verwenden, würden Sie versuchen, auf den Speicher des (jetzt nicht mehr vorhandenen) lokalen Parameters zuzugreifen, und Ihr Programm würde wahrscheinlich abstürzen.
Ich stimme der Lösung von Commodore zu. Aber man muss seine Linie ändern
((ButtonObj)->*(ButtonFunc))();
da ButtonObj ein ist Zeiger widersprechen.
Das ist eine ziemlich … obskure Lösung.
– Josh Matthews
25. September 2008 um 4:17 Uhr
Ja, es ist undurchsichtig. 🙂 Es gibt jedoch noch Delphi- und C++Builder-Legacy-Code im Firmenland. Am besten gründlich.
– Parappa
15. Oktober 2008 um 23:26 Uhr
9644000cookie-checkWie übergeben Sie einen Member-Funktionszeiger?yes