Forum: PC-Programmierung CPP Std::Bind


von ISP-Takt (Gast)


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

von Klaus W. (mfgkw)


Lesenswert?

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?

von Rolf M. (rmagnus)


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.

von ISP-Takt (Gast)


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
}

von Klaus W. (mfgkw)


Lesenswert?

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.

von ISP-Takt (Gast)


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

von Rolf M. (rmagnus)


Lesenswert?

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.

von Klaus W. (mfgkw)


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"

von Klaus W. (mfgkw)


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)

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
Noch kein Account? Hier anmelden.