Generische Pointer auf Methoden



  • Hallo,

    ich möchte eine Funktionalität wie die des Observer Patterns in C++ nachbauen, allerdings ohne Vererbung!!

    Wenn ich Pointer auf Methoden verwenden würde, müsste ich doch die Klasse, auf die der Pointer zeigt, kennen.

    Beispiel:

    class B;
    
    typedef int (B::*funptr) (int);
    

    Ich schreibe eine Wiederverwendbare Klasse und kann heute nicht sagen, welche Klassen meine Klasse in 5 Jahren verwenden werden. Deshalb kann ich diese Variante nicht nehmen.

    Ich möchte im wesentlichen eine Methode Subcribe anbieten, die einen generischen Methodenzeiger als Parameter erwartet. Benutzer meiner Klasse können sich über diese Methode bei meiner Klasse regristrieren. Wenn in meiner Klasse Informationen verfügbar sind, möchte ich diesen Methodenzeiger aufrufen, damit der jeweilige Benutzer weiß, dass Informationen vorhanden sind.

    Hat jemand eine Idee wie ich es machen könnte?



  • Paddy82 schrieb:

    Hat jemand eine Idee wie ich es machen könnte?

    boost.function bietet dir alles was du dazu brauchst.



  • Wie genau würde das Aussehen?

    Ich muss ja eine Subscribe Methode anbieten, bei der sich der Benutzer anmeldet. Als Parameter muss er mir einen Zeiger auf seine Notify-Methode übergeben.
    Wenn ich nun Daten empfange, rufe ich einfach seinen Pointer auf und er kann innerhalb seiner Notify-Methode die Daten bei mir abholen.

    Die Benutzer-Klasse kann total unterschiedlich sein. Z.B. Heute gibt es eine Klasse X morgen eine Klasse Y und in 3 Jahren eine Klasse Z, die diese Subscribe Methode benutzen wollen.

    In dem Tutorial von boost::function gibt es diese Variante:

    struct X {
      int foo(int);
    };
    
    boost::function<int (X*, int)> f;
    
    f = &X::foo; <-- Ausprägung
    
    X x;
    f(&x, 5);
    

    bekomme ich also als Paramter meiner Subcribe-Methode ein ausgeprägtes f (s.o.) übergeben und kann nun einfach f aufrufen?

    Wie würde dann die Signatur meiner Subscribe-Methode aussehen?

    void MyClass::Subscribe(boost::function<????>)
    

    An dieser Stelle darf kein Klassenname stehen.

    Bitte klär mich auf Hume



  • boost::function1<void, TypDesErstenParameters> f;
    f = boost::bind(&Klasse::Memberfunction, ZeigerAufDieInstanz, _1);
    f(parameter);
    


  • boost::function1<void, TypDesErstenParameters> f;
    f = boost::bind(&Klasse::Memberfunction, ZeigerAufDieInstanz, _1);
    f(parameter);
    

    aber wie du eben beschrieben hast,

    boost::bind(&Klasse::....
    

    kann es nicht gehen, da ich &Klasse nicht angeben kann, da ich gar nicht weiß, welche Klassen meine Klasse benutzen werden.

    Ich glaub ich steh gerade auf der Leitung... 😞

    Kann man nicht das "fertige" f (also nach dem bind) als parameter in meiner Methode übergeben? also z.B.

    boost::function1<void, TypDesErstenParameters> f;
    f = boost::bind(&Klasse::Memberfunction, ZeigerAufDieInstanz, _1);
    
    TestKlasse.Subscribe(f);
    

    und in der Subscribe Methode:

    f();
    


  • Die Klasse muss man immer angeben, auch wenn man sich gerade in der selben Klasse befindet. Wenn du die Klasse umbemnenst musst du es an der Stelle auch ändern. Aber das stellt doch nicht wirklich ein Problem dar?!

    Ja so sollte es gehen mit der Übergabe.



  • Doch das stellt an der Stelle ein Problem dar, da ich heute nicht wissen kann, welche klassen mich irgendwann mal benutzen werden! Wenn der Benutzer selbst die Informationen über sich in die Boost::function füllt und sie dann in meine Klasse gibt, dann wird es funktionieren.

    Noch mal zur Erläuterung:
    Benutzer:

    class CBenutzer
    {
       CBenutzer();
       void update();
    
       CServer myServer;
    };
    
    CBenutzer::CBenutzer()
    {
        boost::function1<void, void> f;
        f = boost::bind(&CBenutzer::update, this, _1);
    
        myServer.Subscribe(f);
    
    }
    

    Server:

    CServer::Subscribe(????)
    {
       store(f);
       if(gotData)
       {
          f();
       }
    }
    

    Was muss ich an der Stelle mit den Fragezeichen angeben, damit ich das Boost::Function Template übergeben kann?



  • Ich könnte dein Problem ja verstehen wenn man dauernd bei Subscribe was ändern müsstest wenn eine neue Klasse benutzt werden soll. Aber dank boost::function ist das ja nicht so.

    Für eine Funktion ohne Parameter nimmt man boost::function0.

    Und Subscribe muss dann natürlich so aussehen:

    CServer::Subscribe(const boost::function0<void>& f)
    


  • Danke!!!

    Genau das ist es doch, was ich die ganze Zeit von Dir hören wollte 😉

    Ich biete in meiner Klasse also eine Methode Subscribe mit der Signatur:

    CServer::Subscribe(const boost::function0<void>& f)
    

    an.

    Die Leute, die meine Subscribe- Methode benutzen wollen, müssen boost::function0 ausprägen und mir geben.

    Wenn ich Daten für die Personen habe, rufe ich einfach deren boost::functions auf und sie wissen bescheid, dass sie sich ihre daten abholen können.




Anmelden zum Antworten