Methodenaufruf mittels Methodenzeiger aus anderer Klasser heraus
-
Hi,
ich habe folgendes Problem:
ich habe eine Klasse (nennen wir sie mal A), welche eine Funktion (foo) hat, die einen Funktionspointer als Parameter erwartet. Also etwa so:class A{ public: int foo(int (*func)(int)); }; int A::foo(int (*func)(int)){ return func(1); }soweit so gut. Jetzt gibt es noch andere Klassen, welche die Methode foo aufrufen und eine eigene Methode als Funktionszeiger übergeben sollen. Also etwa so:
#include "A.h" class B{ public: int test(); int handler(int); int daten; }; int B::test(){ A a; return a.foo(handler); } int B::handler(int x){ return x+daten; }und zb. noch
#include "A.h" class C{ public: int test(); int handler(int); int daten; }; int C::test(){ A a; return a.foo(handler); } int C::handler(int x){ return x-daten; }dann noch eine main dazu:
#include "B.h" #include "C.h" int main(){ B b; C c; b.daten = 1; c.daten = 2; printf("B: %d\n",b.test()); printf("C: %d\n",c.test()); }Das Problem liegt jetzt darin, dass ich die Methode nicht so wie in dem Beispiel oben direkt übergeben kann (a.foo(handler); funktioniert nicht, da handler vom Typ int ( B:: )(int) bzw. int ( C:: )(int) ist und eben nicht int (*)(int) ).
Seht ihr eine Möglichkeit das Problem zu umgehen etc.?.. natürlich sollen die Funktionen etwas anderes machen, aber um das Prinzip zu diskutieren ist es vllt einfacher ein primitives (und in diesem Fall sinnloses) Beispiel zu nehmen

In dem Fall würde ich wollen, dass der Aufruf b.test(); als Ergebnis 2 liefert:
B::test() -> A::foo() -> B::handler(1) => 2 => 2entsprechend:
C::test() -> A::foo() -> C::handler(1) => -1 => -1
-
Es gibt in TR1 und C++11 Templates std::tr1::function und std::tr1::bind bzw. std::function und std::bind, mit denen man das machen könnte:
void call_with_one(std::tr1::function<void(int)> const &func) { func(1); } class A { public: void foo(int) { } void bar() { call_with_one(std::tr1::bind(&A::foo, this, std::tr1::placeholders::_1)); } };...für _1, _2 etc. ist eine using-Direktive empfehlenswert, wenn man das ernsthaft betreibt.
Wenn dein Compiler TR1 und C++11 nicht beherrscht, gibt es das auch in Boost.
-
Hi,
danke für die Antwort. Das kannte ich noch nicht. Aber nachdem ich mir das mal (zumindest grob) angeschaut hab seh ich ehrlich gesagt noch nicht, wie das mein Problem löst. Vllt steh ich grad auch nur gewaltig auf dem Schlauch.
Mein Problem liegt ja darin, dass die Funktion foo der Klasse A eine Methode von einem Objekt aufrufen muss, welches sie nicht kennt. Also beim ersten Aufruf muss ja B::handler(1) aufgerufen werden, das Objekt b der klasse B wurde aber in der main angelegt und wird auch nicht an die Klasse A weitergereicht (bzw. das Objekt a)
Mit dem bind könnte ich jetzt in der Methode test die Methode foo an this binden, aber dann müsste foo als Parameter ein Objekt der Klasse B annehmen. Damit wäre es aber auf diese Klasse spezialisiert.Ein anderer Gedanke, der mir jetzt gerade noch gekommen ist wäre es mit einer Template-Klasse zu probieren.
Falls ich auf eien Grünen Zweig komm meld ich mich nochmal. Falls mir jemand erklären kann wie mich das bind weiterbringt - vielen Dank

Steffen
PS: Compiler müsste glaube ich der GCC sein (mit Eclipse unter Linux). Eclipse scheint C++11 noch nicht zu "kennen" (zumindest der automatische Syntax-Check nicht), aber der compiler kanns.
-
Bärtierchen schrieb:
Eclipse scheint C++11 noch nicht zu "kennen" (zumindest der automatische Syntax-Check nicht), aber der compiler kanns.
Eclipse kennt die vom Compiler vordefinierte Konstante __GXX_EXPERIMENTAL_CXX0X__ nicht. Du muss es unter "Path and Symbols" in den Projekteinstellungen eintragen (achte darauf, dass du bei C++ einträgst). Dann funktioniert es.
-
Ich verstehe nicht, wo du das Problem siehst. Mal 1:1 mit TR1 auf deinen Code umgemünzt:
#include <iostream> // das tr1/-Präfix ist gcc-spezifisch. Ggf. kann man das per Präprozessor // portabel machen; ansonsten ist das alles in C++11 im Header <functional> // und direkt im namespace std. #include <tr1/functional> class A{ public: int foo(std::tr1::function<int(int)> const &func); }; int A::foo(std::tr1::function<int(int)> const &func) { return func(1); } class B{ public: int test(); int handler(int); int daten; }; int B::test(){ using std::tr1::placeholders::_1; using std::tr1::bind; A a; return a.foo(bind(&B::handler, this, _1)); } int B::handler(int x){ return x+daten; } class C{ public: int test(); int handler(int); int daten; }; int C::test(){ using std::tr1::placeholders::_1; using std::tr1::bind; A a; return a.foo(bind(&C::handler, this, _1)); } int C::handler(int x){ return x-daten; } int main() { B b; C c; b.daten = 1; c.daten = 2; std::cout << "B: " << b.test() << "\n" "C: " << c.test() << '\n'; }