S
leb0rtran schrieb:
class Klasse2
{
private:
void* object;
void* methode;
public:
Klasse2(void* obj, void* mth) {
this->object = obj;
this->methode = mth; }
void Exec() {
//Hier soll nun die methode von object ausgeführt werden
object->methode(); }
};
Vom Ansatz er gar nicht so verkehrt. Die "Methoden" (in C++ "Elementfunktionen" genannt) sind ja eigentlich nur Funktionen, die zusätzlich auf irgend eine Art und Weise den this-Zeiger bekommen. Das ist allerdings implementierungsabhängig und es gibt keine Standard-konforme Syntax, Elementfunktionen anand von void*-Zeigern auf zu rufen. Der eine oder andere Compiler (zB GCC) besitzt Erweiterungen, mit denen Du Elementfunktionszeiger zu normalen Funktionszeigern konvertieren kannst. Ich würde Dir aber davon abraten. Dass würde ich erst anfassen, wenn alles andere zu langsam ist. Es gibt auch noch eine Falle bzgl. der Anpassung von Zeigern (base/derived pointer adjustments), auf die man aufpassen muss.
Lösung 1: Verwende std::tr1::function oder boost::function
Lösung 2: einfachen Wrapper selbst bauen:
#include <iostream>
#include <cassert>
template<class Clazz, void (Clazz::*Pmf)()>
class simple_memfun_proxy // 0 args, non-const memfun --> void
{
public:
static void invoke(void* obj) {
return (static_cast<Clazz*>(obj)->*Pmf)();
}
};
class Delegate
{
static void null_func(void*) {assert(false);}
void *obj;
void (*fun)(void*);
public:
Delegate() : obj(0), fun(&null_func) {}
template<class T, class Clazz, void (Clazz::*Pmf)()>
Delegate(T* o1, simple_memfun_proxy<Clazz,Pmf>) {
Clazz* o2 = o1; // for implicit pointer adjustments
obj = o2; // must NOT convert o1 directly to void* !!!
fun = &simple_memfun_proxy<Clazz,Pmf>::invoke;
}
bool valid() const {return fun!=&null_func;}
void operator()() const {
return fun(obj);
}
};
#define MAKE_DELEGATE(ObjPtr,Klazz,FuncName) \
Delegate(ObjPtr, \
simple_memfun_proxy<Klazz,&Klazz::FuncName>())
class K {
int zz;
public:
explicit K(int z) : zz(z) {}
void boo() {
std::cout << zz << '\n';
}
};
int main()
{
K k (23);
Delegate d = MAKE_DELEGATE(&k,K,boo);
d();
}
So funktioniert das natürlich nur für Elementfunktionen, die keine weiteren Parameter benötigen, nicht const sind und auch nichts zurückgeben. Um auch const-Elementfunktionen zu unterstützen, oder solche, die mehrere Parameter annehmen können bzw etwas zurück geben können, ist dann etwas mehr Code nötig.
Wie's funktioniert? Im Prinzip wird durch das erste Klassen-Template eine freie Funktion pro Klassen/MemberFunction-Kombination generiert, welche den Aufruf weiterleitet, dafür aber eine einheitliche und Klassen/Methoden-agnostische Schnittstelle anbietet.