Ich danke euch für die zahlreichen Anregungen zu der Problemstellung. Eine Callback-Klasse kommt leider aufgrund des Overhead an Quellcode (Klassendeklaration, Ctor, virtual Dtor, virtuelle callHandler, etc.) im Vergleich zu der Uebergabe eines Funktionpointers (lediglich Funktionsdefinition-/deklaration und Uebergabe der Adresse) nicht in Frage. Es geht weniger um Performance als um Menge an Code die in den zahlreichen abgeleiteten Klassen zu definieren sind. Die begründung hört sich vielleicht etwas unverständlich an, macht jedoch Sinn, wenn man bedenkt, dass von der Basisklasse _sehr_viele_ Klassen abgeleitet, geschrieben und verwaltet werden müssen.
Die Lektüre des angegebenen Links ergab, dass der Weg über Templates wohl der einzig gangbare ist. Ich habe dies nun wie folgt gelöst (der angegebene Quellcode wurde wieder aus den Orginalquellen abstrahiert. Er dient lediglich der Darstellung der Umsetzung und beinhaltet sicherlich einige in der schnelle eingeschobene syntaktische Fehler die jedoch bei der Darstellung des Prinzips ruhig vernachlässig werden können) ;
Code:
class myInterface {
public:
virtual void callPointer(char* name) {} //dummy um bei Bedarf nach myInterface* casten zu koennen und callPointer aufrufen zu koennen ohne T in myClass zu kennen.
};
template<class T> class myClass : public myInterface {
public:
typedef void(T::*FunctionPtr)();
void addPointer(char* name, FunctionPtr f) { //Zum Zeitpunkt da die Funktion hinzugefuegt wird, ist T bekannt. Zum Zeitpunkt des Aufrufes jedoch nicht mehr.
mymap.replace(name, f);
}
virtual void callPointer(char* name) {
FunctionPtr f = mymap[name];
T *self = static_cast<T*>(this); //Hier haben wir den von "locus vivendi" so richtig erwaehnten static_cast. Danke an der Stelle fuer den Hint :-)
(self->*f)(); //Der Aufruf. Entspr. Gültigkeitsprüfungen wurden für dieses Beispiel weggelassen.
}
private:
map<char*,FunctionPtr> mymap;
};
class myInheritedClass : public myClass<myInheritedClass> {
public:
void myfunc() {cout << "inherited";}
void JustToTest() {
addPointer("myfunc", &myInheritedClass::myfunc); //Zuordnung char* => function
callPointer("myfunc"); //Der eigentliche Funktionsaufruf kann dann von ueberall aus geschehen. Eine Uebergabe der zugehoerigen myInheritedClass-Instanz ist nicht mehr erforderlich, da sich callPointer ja bereits auf die zugehoerige Instanz bezieht (z.B. myInheritedClassInstanz->callPointer(...))
}
};
Lesezeichen