Hi, ich habe ein wenig mit der C++ Programmierung angefangen und stehe im Moment vor einem kleinen Problem. Ich möchte gerne Methoden einer Klasse dynamisch aufrufen. Normalerweise würde ich das über ein Array von Funktionpointern machen. Nun ist es scheinbar nicht möglich Funktionspointer auf Methoden einer Klasse zu erstellen (oder es ist nicht schön). Über std::tr1::bind ist es jedoch möglich Methoden dynamisch aufzurufen. Ein Aufruf sieht in etwa so aus: std::tr1::function <void(int)> callback; callback = std::tr1::bind(&MyClass::myMethod,this,std::tr1::placeholders::_1); Da ich das ganze recht einfach gestellten möchte, hätte ich gerne eine Methode die nur die Argumente (&MyClass::myMethod) aufnimmt und das binding innerhalb der Methode geschieht. Ist das möglich, bzw. welchen Typ muss das Argument einer solchen Methode haben oder gibt es andere Möglichkeiten ein solches Vorhaben zu realisieren. Es tut mir weiterhin leid wenn ich mich falsch ausgedrückt habe was die Begrifflichkeiten zu C++ angehen, wie gesagt stehe ich noch am Anfang. Grüße ISP-Takt
ISP-Takt schrieb: > Nun ist es scheinbar nicht möglich Funktionspointer auf Methoden einer > Klasse zu erstellen (oder es ist nicht schön). Warum soll das nicht gehen? Was hast du denn genau vor? Wofür callback?
ISP-Takt schrieb: > Nun ist es scheinbar nicht möglich Funktionspointer auf Methoden einer > Klasse zu erstellen (oder es ist nicht schön). Möglich ist das schon. Es funktioniert allerdings etwas anders, als bei normalen Funktionen. Was verstehst du unter "nicht schön"? So macht man es:
1 | #include <iostream> |
2 | class Klasse |
3 | {
|
4 | public:
|
5 | void myfunc(int arg) |
6 | {
|
7 | std::cout << "Hello, world, the answer is " << arg << "!\n"; |
8 | }
|
9 | |
10 | };
|
11 | |
12 | int main() |
13 | {
|
14 | void (Klasse::*func)(int) = &Klasse::myfunc; |
15 | |
16 | Klasse k; |
17 | (k.*func)(42); |
18 | }
|
> Über std::tr1::bind ist es jedoch möglich Methoden dynamisch aufzurufen. Ein > Aufruf sieht in etwa so aus: > > std::tr1::function <void(int)> callback; > callback = > std::tr1::bind(&MyClass::myMethod,this,std::tr1::placeholders::_1); Und das findest du schön? > Da ich das ganze recht einfach gestellten möchte, hätte ich gerne eine > Methode die nur die Argumente (&MyClass::myMethod) aufnimmt und das > binding innerhalb der Methode geschieht. Naja, der Zweck von std::tr1::bind ist ja gerade, es vorher zu binden. Nur dafür ist es da. > Es tut mir weiterhin leid wenn ich mich falsch ausgedrückt habe was die > Begrifflichkeiten zu C++ angehen, wie gesagt stehe ich noch am Anfang. Das ist kein Problem, aber es ist unklar, wozu du das überhaupt brauchst. Normalerweise benötigt man das äußerst selten. Ich hab bisher nur einmal gedacht, daß ich es brauche, hab's aber dann doch anders gelöst. Deshalb ist es ungewöhnlich, wenn du das als Anfänger schon gleich benötigst.
Hallo, danke für die Antwort ich habe noch mal ein Beispiel an dem es vill. deutlich wird. Ohne die auskommentierte Zeile kann man es normal mit compelierten. Mit gibt es den Fehler: "ISO-C++ verbietet das Ermitteln der Adresse einer nicht qualifizierten oder geklammerten nicht-statischen Elementfunktion, um einen Zeiger auf Elementfunktion zu erzeugen." Die UnknownClass schreibe ich nicht selber von da her kenne ich die Methoden nicht. Diese sollen dann trotzdem über einen Index oder etwas Ähnliches aufgerufen werden können. Daher der Unterbau über die BaseClass.
1 | #include <iostream> |
2 | #include <sstream> |
3 | #include <cstring> |
4 | #include <stdlib.h> |
5 | |
6 | using namespace std; |
7 | |
8 | class BaseClass { |
9 | public: |
10 | |
11 | BaseClass() { |
12 | _anyEvent = NULL; |
13 | } |
14 | |
15 | ~BaseClass() {} |
16 | |
17 | // Funktionspointer hinzufügen |
18 | void add(void (*inp)(int anyInt)) { |
19 | _anyEvent = inp; |
20 | } |
21 | |
22 | void start(void) { |
23 | // Funktion aufrufen |
24 | _anyEvent(5); |
25 | } |
26 | |
27 | private: |
28 | // Funktionspointer |
29 | void (*_anyEvent)(int anyInt); |
30 | }; |
31 | |
32 | |
33 | class UnknownClass : public BaseClass { |
34 | public: |
35 | |
36 | UnknownClass() : BaseClass() { |
37 | _a = 0; |
38 | // Das funktioniert nicht |
39 | // add(&makeA); |
40 | } |
41 | |
42 | void makeA(int inp) { |
43 | _a = inp; |
44 | } |
45 | |
46 | void makeB(int inp) { |
47 | _a = inp; |
48 | } |
49 | |
50 | private: |
51 | int _a; |
52 | }; |
53 | |
54 | |
55 | int main() |
56 | { |
57 | UnknownClass tmp = *new UnknownClass(); |
58 | // Hier soll makeA gestartet werden |
59 | tmp.start(); |
60 | |
61 | } |
Möchtest du einen Zeiger a) auf eine Methode (zu einem Element zugehörig), oder b) zu einer von einem Element unabhängigen Funktion (globale Funktion oder statische Methode)? Das sind zwei grundverschiedene Dinge.
Hallo, ich möchte einen Zeiger der auf eine Methode innerhalb einer Klasse zeigt und es ermöglicht diese Methode innerhalb diese Klasse bzw. der Instanz über den Funktionspointer aufzurufen. Von da her Möglichkeit 1. Grüße ISP-Takt
Warum nutzt du nicht Polymorphie, also machst eine Basisklasse mit einer virtuellen Memberfunktion und leitest für makeA und makeB jeweils eine Klasse ab? Das ist der von C++ vorgesehene Weg, sowas zu tun.
ISP-Takt schrieb: > ich möchte einen Zeiger der auf eine Methode innerhalb einer Klasse > zeigt und es ermöglicht diese Methode innerhalb diese Klasse bzw. der > Instanz über den Funktionspointer aufzurufen. Wie aufrufen? Für ein Objekt der Klasse oder nicht? Genau das ist der springende Punkt. Rolf Magnus schrieb: > Polymorphie wahrscheinlich der bessere Weg, ja. Man kann Polymorphie aber auch von Hand bauen, wenn man will :-) Aber vielleicht will er aus irgendwelchen Gründen das nicht an die Klasse kleben, sondern zur Laufzeit wild wechseln. Schwer zu sagen... PS: bin ja blind. Möglichkeit a entfällt, weil du in makeA() ja auf ein Element der Klasse zugreifst. Also brauchst du einen Zeiger auf eine Methode -> wie oben von Rolf Magnus beschrieben Beitrag "Re: CPP Std::Bind"
Dein Beispiel von oben kann man zum Laufen vergewaltigen, wenn man es so umbaut (ohne den Anspruch, halbwegs elegant zu sein - nur der Form halber):
1 | #include <iostream> |
2 | #include <sstream> |
3 | #include <cstring> |
4 | #include <stdlib.h> |
5 | |
6 | using namespace std; |
7 | |
8 | class BaseClass { |
9 | public:
|
10 | |
11 | BaseClass() |
12 | {
|
13 | _anyEvent = NULL; |
14 | }
|
15 | |
16 | ~BaseClass() {} |
17 | |
18 | // Funktionspointer hinzufuegen
|
19 | void add(void (BaseClass::*inp)(int anyInt)) |
20 | {
|
21 | _anyEvent = inp; |
22 | }
|
23 | |
24 | void start(void) { |
25 | // Funktion aufrufen
|
26 | (this->*_anyEvent)(5); |
27 | }
|
28 | |
29 | virtual void out( std::ostream &os ) const |
30 | {
|
31 | os << "((BaseClass) _anyEvent=" << (void*)_anyEvent << ")"; |
32 | }
|
33 | |
34 | private:
|
35 | // Funktionspointer
|
36 | void (BaseClass::*_anyEvent)(int anyInt); |
37 | };
|
38 | |
39 | |
40 | class UnknownClass : public BaseClass |
41 | {
|
42 | public:
|
43 | |
44 | UnknownClass() : BaseClass() |
45 | {
|
46 | _a = 0; |
47 | // Das funktioniert, wenn auch unelegant
|
48 | add((void (BaseClass::*)(int))&UnknownClass::makeA); |
49 | }
|
50 | |
51 | void makeA(int inp) |
52 | {
|
53 | std::cout << "makeA()" << std::endl; |
54 | _a = inp; |
55 | }
|
56 | |
57 | void makeB(int inp) |
58 | {
|
59 | std::cout << "makeB()" << std::endl; |
60 | _a = inp; |
61 | }
|
62 | |
63 | virtual void out( std::ostream &os ) const |
64 | {
|
65 | os << "((UnknownClass)"; |
66 | BaseClass::out( os ); |
67 | os << ",_a=" << _a << ")"; |
68 | }
|
69 | |
70 | private:
|
71 | int _a; |
72 | };
|
73 | |
74 | std::ostream &operator<<( std::ostream &os, const BaseClass &b ) |
75 | {
|
76 | b.out( os ); |
77 | return os; |
78 | }
|
79 | |
80 | int main() |
81 | {
|
82 | UnknownClass tmp = *new UnknownClass(); |
83 | std::cout << "tmp ist " << tmp << std::endl; |
84 | // Hier soll makeA gestartet werden
|
85 | tmp.start(); |
86 | std::cout << "tmp ist " << tmp << std::endl; |
87 | }
|
Ausgabe:
1 | tmp ist ((UnknownClass)((BaseClass) _anyEvent=0x8048b38),_a=0) |
2 | makeA() |
3 | tmp ist ((UnknownClass)((BaseClass) _anyEvent=0x8048b38),_a=5) |
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.