Hallo zusammen,
ich versuche eine Klasse zuschreiben in der sich eine Callback Funktion
befindet. Ich möchte sie als nicht-statischen deklariert,weil ich in der
Callback-Funktion die anderen member Funktion und die andern Membern
Werte zugreifen möchte. meine Frage Ob es möglich ist, denn die meisten
beispiele und mein Programm kriege ich zum laufen nur wenn die
Callbackfunktion als globale Funktion definiere oder als statische
Funktion.
Hier ist mein Code:
myclass.hpp
1
//void * callBackFunction(void *arg) ; //callback als globale Funktion
2
class myClass
3
{
4
5
public:
6
myClass();
7
void flaeche();
8
void creatTreads();
9
void* callBackFunction(void *arg);
10
//static void* callBackFunction(void *arg);
11
vtkSmartPointer <vtkMultiThreader> threads;
12
private:
13
double breite ;
14
double laenge;
15
};
myclass.cpp
1
myClass::myClass(){
2
3
this->laenge = 0.0;
4
this->breite = 0.0;
5
6
}
7
8
void* myClass::callBackFunction(void *arg ){
9
10
// explicitly cast to a pointer
11
int id = *((int *)arg); // process ID
12
myClass *mySelf = (myClass*) arg;
13
mySelf->flaeche();
14
15
std::cout<<"thread Function: process :prozess.id="<<id<<std::endl;
:104:57: error: invalid use of member function (did you forget the ‘()’ ?)
Wie könnte man diese Problem umgehen? Die CallBackfunktion als static
deklarieren aber wie kann man auf den aktullen Object zugreifen oder
gibts auch andere Lösungen?
Danke schön mal im Voraus
Jojo
Man kann das schon machen, allerdings ist das in C++ wenig hilfreich.
Du kannst den Funktionspointer nicht so machen
void* callBackFunction(void *arg);
Denn der Funktionspointer soll ja nicht auf eine freistehende Funktion
zeigen, sondern auf eine Memberfunktion. Eine Memberfunktion gehört aber
zu einer bestimmten Klasse, daher muss in der Deklaration des
Funtkionspointers auch der Name der Klasse auftauchen.
http://www.parashift.com/c++-faq/pointers-to-members.html
2-tens hilft dir der Funktionspointer nicht viel. Denn du brauchst ja
auch immer ein Objekt, für das eine Funktion aufgerufen werden soll. Ein
Funktionspointer alleine speichert diese Information aber nicht.
D.h. Member-Callbackpointer sind in C++ meistens nicht das was man will.
Will man unbedingt mit Funktionspointern arbeiten, dann geht man
meistens über eine freistehende Funktion (also keine Memberfunktion) und
aus dieser Funktion heraus ruft man dann die Memberfunktion für ein
spezifisches Objekt auf.
Oft aber ist der ganze Ansatz mit Callbackpointer schon der falsche Weg.
Was man statt dessen macht, ist eine Basisklasse mit einer virtuellen
Funktion, die vom Caller aufgerufen wird. Die eigentliche Callbackklasse
leitet sich dann von dieser Klasse ab und implementiert ihrerseits dann
diese virtuelle Funktion. Der Caller bekommt dann einen Pointer auf so
ein Objekt und ruft mit diesem Objekt-Pointer die Funktion auf - der
'virtual' Mechanismus sorgt dann dafür, dass die richtige Funktion
aufgerufen wird.
Viele Problemstellungen löst man in C++ dadurch, dass man in der
Klassenhierarchie eine Zwischenklasse einzieht, die einfach nur als
gemeinsamer Ankerpunkt dient um dort eine virtuelle Funktion in die
Hierarchie einzubringen, von der man dann weiter arbeiten kann.
Ich kenne das so, dass immer eine statische Function verwendet wird.
Diese bekommt als ersten Parameter den this-Pointer mit, und kann dann
damit die eigentliche Memberfunktion aufrufen.
PittyJ schrieb:> // an die member-function weiterleiten> return pc_This->ServerCallback((ServerControllerData *)p_Data);> } // ServerCB()>> // Member Callback> void* ServerThread::ServerCallback(ServerControllerData *p_Data)> {> }
Hallo Pitty,
Danke Sehr für dein Tipps,
wo ist ServerControllerData deklariert ?
Callbacks auf Member-Funktionen sind an sich kein Problem. Dazu kannst
Du Dir std::mem_fn und boost::function anschauen.
- http://en.cppreference.com/w/cpp/utility/functional/mem_fn
- http://www.boost.org/doc/libs/1_54_0/doc/html/function.html
Boost.Function benutze ich ab und an mal. Deine Member-Funktion hat wie
schon beschrieben als ersten Parameter den this-Pointer auf Dein Objekt.
Mit Boost.Bind kannst Du da schon einen Parameter anknüpfen und damit
aus deinem Funktionspointer auf die Member-Funktion und einem
this-Pointer einen zu Deinem Callback-Typen kompatiblen Funktionspointer
machen.
Jetzt musst Du "nur" noch darauf achten, dass dein Objekt am Leben
bleibt, so lange wie der FUnktionspointer benutzt werden könnte. Das
kann man bspw. mit smart-Pointern lösen, die man statt this bindet.
Die Möglichkeiten sind interessant und vielfältig - kann aber auch jede
Menge kaputtgehen dabei und die Fehlermeldungen des Compilers passen
meisst nicht auf eine DIN-A4 Seite - auch, wenn nur ein Zeichen falsch
ist :)
Rooney
Hallo Buchegger,
Danke sehr für deine Tipps, ich habe deine erste vorschlag eben probiert
und
Karl Heinz Buchegger schrieb:> 2-tens hilft dir der Funktionspointer nicht viel. Denn du brauchst ja> auch immer ein Objekt, für das eine Funktion aufgerufen werden soll. Ein> Funktionspointer alleine speichert diese Information aber nicht.>> D.h. Member-Callbackpointer sind in C++ meistens nicht das was man will.> Will man unbedingt mit Funktionspointern arbeiten, dann geht man> meistens über eine freistehende Funktion (also keine Memberfunktion) und> aus dieser Funktion heraus ruft man dann die Memberfunktion für ein> spezifisches Objekt auf.
und es läuft ohne Problem:
1
voidcallBackFunctionHelper(void*arg);
2
classmyClass
3
{
4
5
public:
6
7
myClass();
8
voidflaeche();
9
vtkSmartPointer<vtkMultiThreader>threads;
10
voidcreatTreads();
11
voidcallBackFunction(void*arg);
12
private:
13
doublebreite;
14
doublelaenge;
15
16
17
};
18
19
myClass::myClass(){
20
21
this->laenge=0.0;
22
this->breite=0.0;
23
cout<<"Konstruktur:"<<endl;
24
}
25
26
voidmyClass::callBackFunction(void*arg){
27
28
intid=*((int*)arg);// process ID
29
this->flaeche();
30
31
// boost::bind(&myClass::flaeche, &mySelf);
32
33
std::cout<<"thread Function: process : gl ="<<gl<<"prozess.id="<<id<<std::endl;
JoJo schrieb:> aber wie du schön erwähnt hast,ist schlechte variante, da der Instanz> global sein muss.
'muss' nicht.
Schau dir mal das von PittyJ weiter oben gepostete Beispiel an. Da wird
der Pointer zum Objekt ebenfalls gespeichert und der Funktion übergeben.
Sinnvollerweise wird man rund um das Gespann
Objektpointer/Funktionspointer eine Klasse legen und diesem
Spezialpointer den Aufruf überlassen. ....
> .ich bin dabei zweite variante zu probieren
... womit man dann mehr oder weniger genau hier landet.
Edit: Und 'old man' zeigt dann auch, wies geht.