und noch eine Frage zu Zeigern auf MemberFunktionen
-
Hallo,
ich versuche, den Compiler zu überreden, dass ich dabei (markierte Zeile im Code) nichts Böses will.
Kann mir jemand mit einem Tipp helfen?
Tausend Dank im Voraus!PS: Die FAQ habe ich schon gelesen
#include <iostream> class A { public: int fA(); }; int A::fA() { return 1; } //---------------------------------------- class B { public: B(); int (A::*pFunc)(); int fB(); }; int B::fB(){ return 2; } B::B() { pFunc = &A::fA; // pFunc = &B::fB; //hier weint der Compiler } //---------------------------------------- int main() { B b; A a; std::cout << (a.*b.pFunc)() << std::endl; return 0; }
-
Geht nicht
int (A::*pFunc)();bedeutet eine menberfunktion der klasse A ohne parameter die int zurückgibt.
B::fB() ist keine menberfunktion von A;
Kurt
-
danke für die rasche antwort!
ZuK schrieb:
B::fB() ist keine menberfunktion von A;
eben!
Die Frage: Was muss ich machen, sodass es doch geht?Sergey
-
1. Möglichkeit
Du machst die Funktionen static und nimmst einen "normalen" Funktionszeiger. Du hast dann natürlich kein Objekt mehr, auf das du in den Funktionen mittels this zugreifen kannst.2. Möglichkeit
Ändere dein Design! Ich frage mich, wozu du einen Funktionszeiger auf eine A Memberfunktion definierst, und diesem dann eine B Memberfunktion zuweisen willst.
-
du willst doch in
std::cout << (a.*b.pFunc)() << std::endl;eine member-funktion von A aufrufen. da kann pFunc sowieso keine memberfunktion von B sein!
wenn pFunc eine member-funktion von B sein soll, dann mußt du sie als
int (B::*pFunc)();deklarieren. dann mußt du pFunc aber auch auf ein objekt von der klasse B anwenden. schließlich kannst du ja auch nicht einfach die istream-methode flush() auf ein vector-objekt anwenden.
-
Vielleicht ein wenig Hintergründinformation zu meiner Frage.
Ich möchte einen einfachen Taskmanager für embedded systems implementieren. Die Polymorphie steht dabei NICHT zur Verfügung!!! Es gibt eine Basisklasse CTask und ich leite davon konkrete Tasks ab. Dabei überlade! ich die Memberfunktion run(), weil hier die eigentliche Funktionalität des Tasks implementiert wird. Die Task-Objekte werden beim Taskmanager registriert. Er trägt sie zum Beispiel in ein Array ein. Beim Auftreten eines Ereignisses, wählt der Taskmanager einen Eintrag und ruft seine run()-Funktion.
Falls man die run()-Funktion als virtual in der Klasse CTask deklariert hat, wird zur Laufzeit die „richtige“ run() aufgerufen. Die Erweiterbarkeit dieser Lösung ist sehr gut. Ich kann tausende Task-Klassen implementieren, und nur die run() überschreiben.ABER! Ich darf ja keine Polymorphie benutzen.
Dann wird immer die run() der Basisklasse aufgerufen.Es gibt natürlich verschiedene Lösungen (z.B. in Tasks irgendwelche Eigenschaften speichern, abfragen und dann entscheiden welche run() aufgerufen wird). Diese haben einen Nachteil – schlechte Erweiterbarkeit. Bei jeder neuen Task-Klasse, muss die Basisklasse CTask geändert werden.
Aus diesem Grund dachte ich, dieses Problem anders zu lösen:
Die Basisklasse hat eine run()-Funktion und einen Zeiger fptr auf eine Memberfunktion.
Ich implementiere in jeder Kindklasse die run() neu, und lasse den geererbten fptr auf die &run dieser Kindklasse zeigen.
Dann müsste der Taskmanager über den fptr immer die „richtige“ run() aufrufen ganz ohne die Polymorphie. Das System wäre genau so erweiterbar, wie mit der Polymorphie.Wenn ein Objekt im Heap-Bereich erzeugt wird, speichert es neben seinen Attributen nur die Referenzen zu den Implementierungen seiner Funktionen im Stack-Bereich. Ich kann dann den Pointer auf eine Memberfunktion darauf zeigen lassen. Dementsprechend kann genau diese Memberfunktion über den Pointer aufgerufen werden.
Lieder meckert der Compiler, wenn ich den Zeiger fptr zu einer Funktion, die nicht von der Basisklasse ist, umbiege. Die Typen passen nicht mehr. Die Funktion soll von der Basisklasse sein.
Sagt mir bitte, falls ich irgendwo Gedankenfehler mache?
Falls nicht, hilft mir bitte, den Compiler auszutricksen.Viele Grüße
Sergej
-
Sorry,
Die Polymorphie steht dabei NICHT zur Verfügung!!!
-----------------------------------------------------------------------------
Ich habe endlich gefunden, wo "Editieren" eigener Beiträge steht.
Ich schäme mich.
-
du könntest es so machen:
class CTask { int (CTask::*RunFunc)(); public: CTask (void *runFunc) : RunFunc(reinterpret_cast<CTask::*()>(runFunc) {} int Run () { return this->RunFunc(); } }; class MyTask: public CTask { int Run (); MyTask() : CTask(Run) {} };du mußt dann allerdings im konstruktor jeder task-klasse den funktionszeiger für Run() in der initialisierungsliste explizit angeben. ohne polymorphismus sehe ich leider keine möglichkeit, dies automatisch zu machen.