Die Frage lautet wie folgt: Betrachten Sie diesen Code:
#include <iostream>
class aClass
{
public:
void aTest(int a, int b)
{
printf("%d + %d = %d", a, b, a + b);
}
};
void function1(void (*function)(int, int))
{
function(1, 1);
}
void test(int a,int b)
{
printf("%d - %d = %d", a , b , a - b);
}
int main (int argc, const char* argv[])
{
aClass a();
function1(&test);
function1(&aClass::aTest); // <-- How should I point to a's aClass::test function?
return 0;
}
Wie kann ich die a
's aClass::test
als Argument verwenden function1
? Ich bin dabei festgefahren.
Ich möchte auf ein Mitglied der Klasse zugreifen.
c++
arguments
parameter-passing
function-pointers
pointer-to-member
Jorge Leitao
quelle
quelle
Antworten:
An der Verwendung von Funktionszeigern ist nichts auszusetzen. Zeiger auf nicht statische Elementfunktionen sind jedoch nicht wie normale Funktionszeiger: Elementfunktionen müssen für ein Objekt aufgerufen werden, das als implizites Argument an die Funktion übergeben wird. Die Signatur Ihrer Mitgliedsfunktion oben ist also
anstatt des Typs, den Sie verwenden möchten
Ein Ansatz könnte darin bestehen, das Element funktionsfähig zu machen.
static
In diesem Fall muss kein Objekt aufgerufen werden, und Sie können es mit dem Typ verwendenvoid (*)(int, int)
.Wenn Sie irgendeine nicht-statische Member der Klasse zugreifen müssen und müssen Sie mit Funktionszeiger halten, zum Beispiel , weil die Funktion Teil einer C - Schnittstelle ist, die beste Wahl ist, immer ein Pass
void*
an Ihre Funktion Funktionszeiger und Anruf unter Ihr Mitglied über eine Weiterleitungsfunktion, die ein Objekt von der erhältvoid*
und dann die Mitgliedsfunktion aufruft.In einer richtigen C ++ - Schnittstelle möchten Sie vielleicht sehen, wie Ihre Funktion ein Vorlagenargument für Funktionsobjekte verwendet, um beliebige Klassentypen zu verwenden. Wenn die Verwendung einer Vorlagenschnittstelle unerwünscht ist, sollten Sie Folgendes verwenden
std::function<void(int, int)>
: Sie können für diese ein geeignet aufrufbares Funktionsobjekt erstellen, zstd::bind()
.Die typsicheren Ansätze, bei denen ein Vorlagenargument für den Klassentyp oder ein geeignetes verwendet wird,
std::function<...>
sind der Verwendung einervoid*
Schnittstelle vorzuziehen, da sie das Fehlerpotential aufgrund einer Umwandlung in den falschen Typ beseitigen.Hier ein Beispiel, um zu verdeutlichen, wie ein Funktionszeiger zum Aufrufen einer Elementfunktion verwendet wird:
quelle
void*
, was bedeutet, dass Sie sehr böse Fehler bekommen können, weil sie nicht mehr geprüft ist.Die Antwort von @Pete Becker ist in Ordnung, aber Sie können dies auch tun, ohne die
class
Instanz als expliziten Parameterfunction1
in C ++ 11 zu übergeben:quelle
void function1(std::function<void(int, int)>)
richtig?void function1(std::function<void(int, int)> functionToCall)
und dannfunctionToCall(1,1);
. Ich habe versucht, die Antwort zu bearbeiten, aber jemand hat sie aus irgendeinem Grund als nicht sinnvoll abgelehnt. Wir werden sehen, ob es irgendwann positiv bewertet wird.Ein Zeiger auf die Elementfunktion unterscheidet sich von einem Zeiger auf die Funktion. Um eine Elementfunktion über einen Zeiger zu verwenden, benötigen Sie (offensichtlich) einen Zeiger darauf und ein Objekt, auf das Sie sie anwenden können. So ist die entsprechende Version von
function1
wäreund um es zu nennen:
quelle
function
invoid (aClass::*function)(int, int)
war eine Art, weil es eine Art isttypedef void (aClass::*function)(int, int)
.typedef int X;
definiert einen Typ;int X;
erstellt ein Objekt.Wenn Sie dies seit 2011 ändern können
function1
, gehen Sie wie folgt vor:( Live-Demo )
Beachten Sie auch, dass ich Ihre defekte Objektdefinition korrigiert habe (
aClass a();
deklariert eine Funktion).quelle
Ich habe eine ähnliche Frage gestellt ( C ++ openframeworks, die von anderen Klassen ungültig sind ), aber die Antwort, die ich gefunden habe, war klarer, daher hier die Erklärung für zukünftige Datensätze:
Es ist einfacher, die std :: -Funktion wie folgt zu verwenden:
und dann anrufen als:
oder noch einfacher:
Hier erstellen Sie ein Lambda, das das Objekt aufruft, das es als Referenz erfasst
quelle
std::function
in verwenden,draw
anstatt ihn bei jedem Aufruf zu kopieren.Ich habe das Mitglied als statisch funktionieren lassen und alles funktioniert:
quelle
Ich bin mir nicht sicher, warum diese unglaublich einfache Lösung verpasst wurde:
Ausgabe:
quelle
Wenn Sie die Instanz tatsächlich nicht verwenden müssen
a
(dh Sie können sie wie die Antwort von @mathengineer statisch machen ), können Sie einfach ein Lambda ohne Capture übergeben. (welche zerfallen zum Funktionszeiger)Wandbox
Hinweis: Wenn
aClass
der Bau teuer ist oder Nebenwirkungen hat, ist dies möglicherweise kein guter Weg.quelle
Sie können jetzt aufhören, Ihre Köpfe zu schlagen. Hier ist der Wrapper für die Member-Funktion zur Unterstützung vorhandener Funktionen, die einfache C- Funktionen als Argumente verwenden.
thread_local
Richtlinie ist hier der Schlüssel.http://cpp.sh/9jhk3
Bitte kommentieren Sie alle Probleme mit diesem Ansatz.
Andere Antworten rufen vorhandene einfache
C
Funktionen nicht auf: http://cpp.sh/8exunquelle
C
Funktionen als Argumente verwenden.