CPP Std::Bind

Gast #2741305
Lesenswert?
• ▲
▼
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
#2741450
Lesenswert?
• ▲
▼
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.
Gast #2741453
Lesenswert?
• ▲
▼
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
}
Gast #2741462
Lesenswert?
• ▲
▼
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
#2741471
Lesenswert?
• ▲
▼
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"
#2741511
Lesenswert?
• ▲
▼
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)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren