PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : C++ Funktionszeiger (Member von Klasse A) auf Funktion von Klasse B



Stanislaus
20-01-2004, 18:04
Moin, moin!

Ich hätte da gerne mal ein Problem.
Ich habe eine Klasse A, die einen Funktionszeiger als Member hat

class A
{
...
void (A::*pFunct)(A);
//void (*pFunct)(A); führt zum selben Problem

};
sowie eine Klasse B, die die entsprechende Funktion beinhaltet

#include "A.h"

class B
{
void createA();
void funct(A);
}

Nun erzeugt Klasse B eine Instanz von A und soll dem Funktionszeiger pFunct von A die Adresse von B::funct zuweisen.

#include "A.h"

void B::createA()
{
A* ding = new A();
ding->pFunct = &this->funct; // FEHLER
}

void funct(A kram)
{
// mache etwas mit kram
}

Anmerkung: Klasse B kennt zwar Klasse A. Klasse A kennt allerdings Klasse B nicht und das soll nach Möglichkeit auch so bleiben :)

Das Problem ist nun die Zuweisung der Funktionsadresse von Klasse B an den Funktionszeiger von Klasse A. Ich hab in ettlichen Tutorials, Büchern und Foren immer wieder den Fall gefunden, daß klassenintern oder aus einer klassenlosen funktion auf eine Memberfunktion zugegriffen wird aber niemals o.g. Fall.
Grundsätzlich ist mir der Fehler auch klar und der Compiler sagt mir ja auch, daß die Umwandung von "void(B::*)(A)" nach "void(A::*)(A)" fehlerhaft ist. Aber an dieser Stelle verlassen mich dann meine Typecast-Fähigkeiten; Soll heißen mir ist schlicht und ergreifend die Schreibweise unklar. Habs auch schon per dynamic_cast versucht aber entweder produziere ich Syntaxfehler oder ungültige Typecasts.

Für eine kurze Erleuchtung wäre ich sehr dankbar und falls o.g. Konstruktion nicht der eleganteste Weg ist lasse ich mich auch gerne belehren :D

Besten Dank und schönen Abend!
Gruß,
Uli

wraith
20-01-2004, 18:23
class B; //Forward-Declaration von Klasse B

class A
{
...
void (B::*pFunct)(A);
};
....
void B::createA()
{
A* ding = new A();
ding->pFunct = &B::funct;
}

Stanislaus
20-01-2004, 18:55
Cool. Vielen Dank das war die Erleuchtung und so prompt!
Forward Deklarationen hab ich unter ObjectPascal schon zig mal verwendet aber so klug, das ganze mal in C++ zu übertragen war ich dann doch nicht :rolleyes:
Auf jeden Fall herzlichen Dank nochmal.

Leider hängts jetzt am Aufruf :(

Laut meiner schlauen Bücher müsste das ganze in etwa so funktionieren.

void A::irgendwas()
{
this->pFunct(this);
// oder
this->*pFunct(this);
}

Allerdings führen beide Versionen zu der Meldung "must use .* or ->* to call pointer-to-member function ..."

Wenn Du mir das auch noch löst geb ich einen aus. (Anfahrt natürlich exclusive) ;)

Sö, werd denn mal weiterforschen...

Bis neulich ...

wraith
20-01-2004, 19:10
Original geschrieben von Stanislaus

Leider hängts jetzt am Aufruf :(

Ja,und gleich siehst du auch,warum man so wenig darüber im I-Net findet.


void B::createA()
{
A* ding = new A();
ding->pFunct = &B::funct;
(this->*ding->pFunct)(*ding);
}

anda_skoa
20-01-2004, 20:25
Latürnich könnte man auch mit einem Interface und virtuellen Methoden arbeiten.

A.h


class I
{
public:
virtual void bar() = 0;
};

class A
{
public:
A(I* i) : m_i(i) {};

void foo() {
if(m_i) m_i->bar();
}
private:
I* m_i;
};




class B : public I
{
public:
void createA() {
A* a = new A(this);
}

void bar() {
}
};


Ciao,
_

Stanislaus
20-01-2004, 21:54
Original geschrieben von wraith
Ja,und gleich siehst du auch,warum man so wenig darüber im I-Net findet.


void B::createA()
{
A* ding = new A();
ding->pFunct = &B::funct;
(this->*ding->pFunct)(*ding);
}


Dank Dir, nur leider ist das nicht das, was ich brauche.
Ich will nicht den Funktionpointer aus Klasse B sondern aus A aufrufen.
Also:

void A::aktionVonA()
{
// und nu?
(*this->pFunct)(*this); // => "invalid use of 'unary *' on pointer to member"
(this->*pFunct)(*this); // => "member type 'B::' incompatible with object type 'A'"
}
Und so stehe ich quasi vor dem selben Typecast-Problem wie zu Beginn :(

@anda_skoda: Danke, aber irgendwie scheint mir diese Konstruktion für meinen Fall nicht sehr nützlich. Oder versteh ich die Funktionsweise einfach nur falsch?! Wo wäre denn jetzt da die Möglichkeit aus A eine Funktion von B aufzurufen und dabei A zu übergeben?

Schönen Abend!

wraith
20-01-2004, 22:23
Original geschrieben von Stanislaus
nur leider ist das nicht das, was ich brauche.
Ich will nicht den Funktionpointer aus Klasse B sondern aus A aufrufen.
Also:

void A::aktionVonA()
{
// und nu?
(*this->pFunct)(*this); // => "invalid use of 'unary *' on pointer to member"
(this->*pFunct)(*this); // => "member type 'B::' incompatible with object type 'A'"
}

Der Zeiger hat die Form void (B::*pFunct)(A);,und das B steht da nicht umsonst.
Du mußt den Zeiger über ein B Objekt aufrufen,in meinem Code war das B das this.Daher wird dein Code so nicht funktionieren,weil ganz links kein B steht.
So würde es gehen:


void A::foo() {
B b; //Ein B Objekt
(b.*pFunct)(*this);
}

Du mußt also irgendwie ein B Objekt bekommen,zumeist wird das so gemacht,das die Funktion foo einen Zeiger auf ein B Objekt mitbekommt.
Man könnte sich auch zu so einem Code hinreißen lassen.


(((B*)0)->*pFunct)(*this); //Achtung,Falsch,Dereferenzierung 0 Pointer.


Btw,ich sehe den Code mehr als Brain-Teaser an ;).

Stanislaus
21-01-2004, 07:48
Original geschrieben von wraith
Der Zeiger hat die Form void (B::*pFunct)(A);,und das B steht da nicht umsonst.
Du mußt den Zeiger über ein B Objekt aufrufen,in meinem Code war das B das this.Daher wird dein Code so nicht funktionieren,weil ganz links kein B steht.
So würde es gehen:


void A::foo() {
B b; //Ein B Objekt
(b.*pFunct)(*this);
}

Du mußt also irgendwie ein B Objekt bekommen,zumeist wird das so gemacht,das die Funktion foo einen Zeiger auf ein B Objekt mitbekommt.
So langsam ist die Verwirrung perfekt. "pFunct" ist doch ein Member von A und nicht von B. Wieso muss A denn nun den Aufruf über eine Instanz von B machen?
Zumal ja Sinn und Zweck der ganzen Angelegenheit war, daß A eben B nicht kennt.

Oder ich frag mal andersrum. Wie würde man das am elegantesten realisieren?
Es soll eine quasi CallBack Funktion werden.
Klasse B erzeugt n Instanzen von Klasse A und übergibt A die Adresse von B::foo(). Jede Instanz von A hat ja nun einen Member pFunct, über den sie dann die entsprechende Funktion von B Aufrufen kann um einen Zeiger auf sich selbts zu übergeben, damit B an A rummanipulieren kann.

Bis neulich ...

anda_skoa
21-01-2004, 08:53
Original geschrieben von Stanislaus
@anda_skoda: Danke, aber irgendwie scheint mir diese Konstruktion für meinen Fall nicht sehr nützlich. Oder versteh ich die Funktionsweise einfach nur falsch?! Wo wäre denn jetzt da die Möglichkeit aus A eine Funktion von B aufzurufen und dabei A zu übergeben?


Das Interface I deklariert eine Funktion.
A hat eine Instanz von I, kann also die Methoden von I aufrufen.

B implementiert das Interface I, d.h. B ist für den Compiler ein I.
Damit kannst du B an A übergeben und A kann die Methode von B aufrufen.

Das ist jetzt nicht auf B bechränkt, jede Klasse, die von I ableiten kann als I an A übergeben werden und A kann dann an der übergeben Instanz auch bar() aufrufen.

Brauchst du ja nur auszuprobieren.

Ciao,
_

Stanislaus
21-01-2004, 10:59
@anda_skoa: DAS ist ja eigentlich genau was ich brauche. Werd ich gleich mal testen.
Dank Dir!