Pointer auf Memberfunktion



  • hi,

    ich will einer Klassen Methode einen Pointer auf eine Methode eine anderen Objekts übergeben

    So in der Art

    class Klasse1
    {
    private:
      int i;
    public:
      Klasse1(int i) { this->i = i; }
      void Methode() { cout << this->i << endl; }
    };
    
    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(); }
    };
    int main()
    {
      Klasse1 k1(5);
      Klasse2 k2(&k1, &k1.methode);
    
      k2.Exec();  //Soll 5 ausgeben
      return 0;
    }
    

    hoffe es ist klar, was ich meine xD
    Schonmal vielen Dank für eure Hilfe

    mfg



  • bin kein c++ spezialist, hätte aber evtl. einen vorschlag wie man das lösen könnte

    #include <iostream>
    using namespace std;
    
    #define METHOD_A 0
    #define METHOD_B 1
    
    class Klasse1
    {
    private:
      int i;
    public:
      Klasse1(int i) { this->i = i; }
      void methodeA() { cout << this->i << endl; }
      void methodeB() { cout << this->i-2 << endl; }
    };
    
    class Klasse2
    {
    private:
      Klasse1 *cls;
      int methode;
    public:
      Klasse2(Klasse1 *c,int m) {
    	  cls = c;
    	  methode = m;
      }
      void Exec() {
    	  switch(methode){
    	  case METHOD_A:
    		  cls->methodeA();
    	  break;
    	  case METHOD_B:
    		  cls->methodeB();
      	  break;
    	  }
      }
    };
    int main()
    {
      Klasse1 k1(5);
    
      Klasse2 k2(&k1,METHOD_B);
      k2.Exec();
      Klasse2 k3(&k1,METHOD_A);
      k3.Exec();
    
      return 0;
    }
    

    lg lolo



  • Hier gibt es ein sehr schönes und ausführliches Tutorial über (Member)-Funktionszeiger:
    http://www.newty.de/fpt/index.html

    Dort findest du genau das, was du suchst.



  • 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.


Anmelden zum Antworten