Die Frage ist die folgende: 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 den aClass::test
des a
als Argument für function1
verwenden? Ich bin dabei fest damit beschäftigt.
Ich möchte auf ein Mitglied der Klasse zugreifen.
Die Verwendung von Funktionszeigern stimmt nicht. 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
void (aClass::*)(int, int)
anstelle des Typs, den Sie verwenden möchten
void (*)(int, int)
Ein Ansatz könnte darin bestehen, die Member-Funktion static
zu erstellen. In diesem Fall muss kein Objekt aufgerufen werden, und Sie können es mit dem Typ void (*)(int, int)
verwenden.
Wenn Sie auf ein nicht statisches Member Ihrer Klasse und zugreifen müssen, müssen Sie bei Funktionszeigern bleiben, z. B. weil die Funktion Teil einer C-Schnittstelle ist. Die beste Option ist, immer einen void*
an Ihre Funktion zu übergeben Nehmen Sie die Funktionszeiger und rufen Sie Ihr Mitglied über eine Weiterleitungsfunktion auf, die ein Objekt aus dem void*
abruft und dann die Mitgliedsfunktion aufruft.
In einer richtigen C++ - Schnittstelle können Sie einen Blick darauf werfen, dass Ihre Funktion ein Templatargument für Funktionsobjekte verwendet, um beliebige Klassentypen zu verwenden. Wenn die Verwendung einer Schnittstelle mit Vorlagen nicht erwünscht ist, sollten Sie etwas wie std::function<void(int, int)>
verwenden: Sie können ein entsprechend aufrufbares Funktionsobjekt für diese erstellen, z. B. mit std::bind()
.
Die typsicheren Ansätze mit einem Vorlagenargument für den Klassentyp oder einem geeigneten std::function<...>
sind gegenüber der Verwendung einer void*
-Schnittstelle zu bevorzugen, da sie das Potenzial für Fehler aufgrund einer Umwandlung in den falschen Typ beseitigen.
Um zu erläutern, wie ein Funktionszeiger zum Aufrufen einer Member-Funktion verwendet wird, folgt ein Beispiel:
// the function using the function pointers:
void somefunction(void (*fptr)(void*, int, int), void* context) {
fptr(context, 17, 42);
}
void non_member(void*, int i0, int i1) {
std::cout << "I don't need any context! i0=" << i0 << " i1=" << i1 << "\n";
}
struct foo {
void member(int i0, int i1) {
std::cout << "member function: this=" << this << " i0=" << i0 << " i1=" << i1 << "\n";
}
};
void forwarder(void* context, int i0, int i1) {
static_cast<foo*>(context)->member(i0, i1);
}
int main() {
somefunction(&non_member, 0);
foo object;
somefunction(&forwarder, &object);
}
Die Antwort von @Pete Becker ist in Ordnung, aber Sie können dies auch tun, ohne die class
-Instanz als expliziten Parameter an function1
in C++ 11 zu übergeben:
#include <functional>
using namespace std::placeholders;
void function1(std::function<void(int, int)> fun)
{
fun(1, 1);
}
int main (int argc, const char * argv[])
{
...
aClass a;
auto fp = std::bind(&aClass::test, a, _1, _2);
function1(fp);
return 0;
}
Ein Zeiger auf eine Elementfunktion unterscheidet sich von einem Zeiger auf eine Funktion. Um eine Elementfunktion über einen Zeiger zu verwenden, benötigen Sie einen Zeiger (offensichtlich) und ein Objekt, auf das sie angewendet werden soll. Die entsprechende Version von function1
wäre also
void function1(void (aClass::*function)(int, int), aClass& a) {
(a.*function)(1, 1);
}
und um es zu nennen:
aClass a; // note: no parentheses; with parentheses it's a function declaration
function1(&aClass::test, a);
Wenn Sie function1
ändern können, tun Sie dies seit 2011:
#include <functional>
#include <cstdio>
using namespace std;
class aClass
{
public:
void aTest(int a, int b)
{
printf("%d + %d = %d", a, b, a + b);
}
};
template <typename Callable>
void function1(Callable f)
{
f(1, 1);
}
void test(int a,int b)
{
printf("%d - %d = %d", a , b , a - b);
}
int main()
{
aClass obj;
// Free function
function1(&test);
// Bound member function
using namespace std::placeholders;
function1(std::bind(&aClass::aTest, obj, _1, _2));
// Lambda
function1([&](int a, int b) {
obj.aTest(a, b);
});
}
Beachten Sie auch, dass ich Ihre defekte Objektdefinition korrigiert habe (aClass a();
deklariert eine Funktion).
Ich habe eine ähnliche Frage gestellt ( C++ openframeworks, die Void von anderen Klassen durchläuft ), aber die Antwort, die ich fand, war klarer, also hier die Erklärung für zukünftige Datensätze:
die Verwendung von std :: function ist einfacher als in:
void draw(int grid, std::function<void()> element)
und dann anrufen als:
grid.draw(12, std::bind(&BarrettaClass::draw, a, std::placeholders::_1));
oder noch einfacher:
grid.draw(12, [&]{a.draw()});
hier erstellen Sie ein Lambda, das das Objekt aufruft, das es als Referenz aufnimmt
Sie können jetzt aufhören, Ihren Kopf zu schlagen. Hier ist der Wrapper für die Member-Funktion zur Unterstützung der vorhandenen - Funktionen, wobei die einfachen C - Funktionen als Argumente verwendet werden. thread_local
Direktive ist hier der Schlüssel.
// Example program
#include <iostream>
#include <string>
using namespace std;
typedef int FooCooker_ (int);
// Existing function
extern "C" void cook_10_foo (FooCooker_ FooCooker) {
cout << "Cooking 10 Foo ..." << endl;
cout << "FooCooker:" << endl;
FooCooker (10);
}
struct Bar_ {
Bar_ (int Foo = 0) : Foo (Foo) {};
int cook (int Foo) {
cout << "This Bar got " << this->Foo << endl;
if (this->Foo >= Foo) {
this->Foo -= Foo;
cout << Foo << " cooked" << endl;
return Foo;
} else {
cout << "Can't cook " << Foo << endl;
return 0;
}
}
int Foo = 0;
};
// Each Bar_ object and a member function need to define
// their own wrapper with a global thread_local object ptr
// to be called as a plain C function.
thread_local static Bar_* BarPtr = NULL;
static int cook_in_Bar (int Foo) {
return BarPtr->cook (Foo);
}
thread_local static Bar_* Bar2Ptr = NULL;
static int cook_in_Bar2 (int Foo) {
return Bar2Ptr->cook (Foo);
}
int main () {
BarPtr = new Bar_ (20);
cook_10_foo (cook_in_Bar);
Bar2Ptr = new Bar_ (40);
cook_10_foo (cook_in_Bar2);
delete BarPtr;
delete Bar2Ptr;
return 0;
}
Bitte kommentieren Sie alle Probleme mit diesem Ansatz.
Andere Antworten schlagen keine vorhandenen einfachen C
-Funktionen vor: http://cpp.sh/8exun
Ich habe die Memberfunktion als statisch und für alle Arbeiten festgelegt:
#include <iostream>
class aClass
{
public:
static void aTest(int a, int b)
{
printf("%d + %d = %d\n", a, b, a + b);
}
};
void function1(int a,int b,void function(int, int))
{
function(a, b);
}
void test(int a,int b)
{
printf("%d - %d = %d\n", a , b , a - b);
}
int main (int argc, const char* argv[])
{
aClass a;
function1(10,12,test);
function1(10,12,a.aTest); // <-- How should I point to a's aClass::test function?
getchar();return 0;
}