Forum: Compiler & IDEs Funktionspointer Verständnisproblem


von Georg (Gast)


Lesenswert?

Also Funktionspointer werden wie gefolgt deklariert.
1
class A 
2
{
3
  public: int doSomething(unsigned int para);
4
  private:
5
      int sum;
6
7
8
};
9
10
typedef int(A::ptr*)(unsigned int);
11
12
ptr=&A::doSomething;  //zeigt auf Adresse von Funktion doSoemthing

Mein Problem:
Die Klasse beinhaltet den Wert sum, welcher durch den Parameter von der 
Methode verändert wird. Von dieser Klasse werden viele Objekte angelegt. 
Meine Frage: Wird durch die obige Zuweisung des Funktionspointer die 
Adresse der Methode des erzeugten Objekts oder.... abgespeichert. D.h: 
Kann ich ein Array, welches die einzelnen Funktionspointer enthält, 
anlegen, wo sie der Reihenfolge von der Erzeugung der Objekte angeordnet 
sind oder muss eine Bindung(Funktor) erfolgen?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Beim Gebrauch von Funktionspointern gibt es keinen this-Pointer, also 
ist kein Zugriff auf Elemente eines zugehörigen Objektes möglich. 
Deswegen sind Memberfunktionen einer Klasse, auf die mit 
Funktionspointern zugegriffen werden soll, auch als static zu 
deklarieren.

Sollte es davon abweichende Möglichkeiten in C++ zu geben, würde ich 
gerne wissen, wie das gehen soll.

von Georg (Gast)


Lesenswert?

Mit einem Funktor zum Beispiel. Übergabeparamter des Operators () sind 
Funktionspointer + Objekt.

von Karl H. (kbuchegg)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Beim Gebrauch von Funktionspointern gibt es keinen this-Pointer, also
> ist kein Zugriff auf Elemente eines zugehörigen Objektes möglich.
> Deswegen sind Memberfunktionen einer Klasse, auf die mit
> Funktionspointern zugegriffen werden soll, auch als static zu
> deklarieren.
>
> Sollte es davon abweichende Möglichkeiten in C++ zu geben, würde ich
> gerne wissen, wie das gehen soll.

Nur der Vollständigkeit halber:
Es geht schon. Aber blöderweise ist dann der Klassenname Teil des 
Datentyps des Funktionspointers. Und damit ist das ganze dann ein wenig 
witzlos.

von Rolf Magnus (Gast)


Lesenswert?

Georg schrieb:
> Also Funktionspointer werden wie gefolgt deklariert.
> class A
> {
>   public: int doSomething(unsigned int para);
>   private:
>       int sum;
>
>
> };
>
> typedef int(A::ptr*)(unsigned int);
>
> ptr=&A::doSomething;  //zeigt auf Adresse von Funktion doSoemthing

ptr ist ein Typedef, keine Variable, also eher:
1
ptr p = &A::doSomething;

> Meine Frage: Wird durch die obige Zuweisung des Funktionspointer die
> Adresse der Methode des erzeugten Objekts oder.... abgespeichert. D.h:
> Kann ich ein Array, welches die einzelnen Funktionspointer enthält,
> anlegen, wo sie der Reihenfolge von der Erzeugung der Objekte angeordnet
> sind oder muss eine Bindung(Funktor) erfolgen?

Die Bindung erfolgt beim Aufruf, z.B. so:
1
A a;
2
a.*p(42);


Rufus Τ. Firefly schrieb:
> Beim Gebrauch von Funktionspointern gibt es keinen this-Pointer, also
> ist kein Zugriff auf Elemente eines zugehörigen Objektes möglich.

Richtig, aber es geht hier um einen Pointer auf eine Memberfunktion, 
nicht um einen normalen Funktionszeiger.

> Sollte es davon abweichende Möglichkeiten in C++ zu geben, würde ich
> gerne wissen, wie das gehen soll.

Na so wie's oben steht.

Karl Heinz Buchegger schrieb:
> Nur der Vollständigkeit halber:
> Es geht schon. Aber blöderweise ist dann der Klassenname Teil des
> Datentyps des Funktionspointers. Und damit ist das ganze dann ein wenig
> witzlos.

Wie sollte das auch sonst gehen? in der Funktion hast du ja einen 
this-Pointer. Wenn das eigentliche Objekt von einem völlig anderen Typ 
wäre, käme ja nur Blödsinn raus.
Was allerdings auch mit Memberzeigern geht, ist Polymporphie.

von Karl H. (kbuchegg)


Lesenswert?

Rolf Magnus schrieb:

>> Es geht schon. Aber blöderweise ist dann der Klassenname Teil des
>> Datentyps des Funktionspointers. Und damit ist das ganze dann ein wenig
>> witzlos.
>
> Wie sollte das auch sonst gehen?

Ich hasse es, das zu sagen:
So wie in C# Delegaten implementiert sind.

von Georg (Gast)


Lesenswert?

Das Problem ist das ich nur einen Parameter übergeben kann(keine 
unterschiedlichen für die einzelnen Objektmethoden). Also gibt es 
wirklich keine Möglichkeiten,Pattern,....etc wo ich auf die Methoden 
über Funktionspointer ohne Refenrenzierung des Objektes zugreifen kann. 
:(

von Rolf Magnus (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> So wie in C# Delegaten implementiert sind.

Sowas läßt sich in C++ nachbilden.
Zum Beispiel etwa in dieser Art:
1
#include <iostream>
2
3
class A
4
{
5
  public: 
6
      int doSomething(unsigned int para)
7
      {
8
          std::cout << "value is " << para << '\n';
9
          return 0;
10
      }
11
12
  private:
13
      int sum;
14
15
};
16
17
template<typename R, typename P>
18
class Delegate
19
{
20
public:
21
    virtual R operator()(P param) = 0;
22
};
23
24
template<typename R, typename O, typename P>
25
class DelegateTmpl : public Delegate<R, P>
26
{
27
public:
28
    DelegateTmpl(O& obj, R (O::*fun)(P))
29
        : obj(obj), fun(fun)
30
    {
31
    }
32
33
    R operator()(P param)
34
    {
35
        return (obj.*fun)(param);
36
    }
37
38
private:
39
    O& obj;
40
    R (O::*fun)(P);
41
};
42
43
template<typename R, typename O, typename P>
44
Delegate<R, P>* delegate(O& obj, R (O::*fun)(P))
45
{
46
    return new DelegateTmpl<R, O, P>(obj, fun);
47
}
48
49
int main()
50
{
51
    A a;
52
    Delegate<int, unsigned int>* fun = delegate(a, &A::doSomething);
53
    (*fun)(3);
54
    delete fun;
55
}

Hier ist schon der Klassenname deinem Wunsch entsprechend aus dem Typ 
rausgenommen. So wie ich den Ursprungsposter verstanden hab, braucht er 
das aber gar nicht. Dann kann man es vereinfachen:
1
#include <iostream>
2
3
class A
4
{
5
  public: 
6
      int doSomething(unsigned int para)
7
      {
8
          std::cout << "value is " << para << '\n';
9
          return 0;
10
      }
11
12
  private:
13
      int sum;
14
15
};
16
17
template<typename R, typename O, typename P>
18
class Delegate
19
{
20
public:
21
    Delegate(O& obj, R (O::*fun)(P))
22
        : obj(obj), fun(fun)
23
    {
24
    }
25
26
    R operator()(P param)
27
    {
28
        return (obj.*fun)(param);
29
    }
30
31
private:
32
    O& obj;
33
    R (O::*fun)(P);
34
};
35
36
template<typename R, typename O, typename P>
37
Delegate<R, O, P> delegate(O& obj, R (O::*fun)(P))
38
{
39
    return Delegate<R, O, P>(obj, fun);
40
}
41
42
int main()
43
{
44
    A a;
45
    Delegate<int, A, unsigned int> fun = delegate(a, &A::doSomething);
46
    fun(3);
47
}

Da ist der Name der Klasse noch drin, aber dafür braucht man keine 
Polymorphie und muß das Delegate nicht dynamisch anlegen. Die Templates 
muß man halt noch ein paarmal duplizieren, da obiges nur Funktionen mit 
genau einem Parameter abdeckt. Sieht erstmal kompliziert aus, aber wenn 
man mal einen Header mit dem Template-Zeugs gefüllt hat, ist das nicht 
mehr so wahnsinnig schlimm. Leider muß man die ganzen Parametertypen als 
Template-Argumente explizit angeben.
In der nächsten C++-Version (C++0x) wird man das nicht mehr brauchen. 
g++ kann's übrigens schon heute, wenn man mit -std=c++0x kompiliert. Da 
vereinfacht sich main() zu folgendem:
1
    A a;
2
    auto fun = delegate(a, &A::doSomething); 
3
    fun(3);

von Rolf Magnus (Gast)


Lesenswert?

Rolf Magnus schrieb:

> template<typename R, typename P>
> class Delegate
> {
> public:
>     virtual R operator()(P param) = 0;
> };

Mir ist gerade noch aufgefallen, daß hier noch der virtuelle Destruktor 
fehlt.

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.