Pointer Casting (SigC++)



  • der_held schrieb:

    @volkrad: Wie funktioniert dein NOCOPY?

    bin wiedermal nicht an meinem rechner. es könnte ungefähr so aussehen:

    class NoCOpy
    {
       private:
       private:
       private:
       NoCOpy(NoCopy const&);
       NoCOpy& operator=(NoCopy const&);
    };
    #ifndef NDEBUG
    #define NOCOPY NoCOpy _noCOpyDummy;
    #else
    #define NOCOPY
    #endif
    


  • Shade Of Mine schrieb:

    Ganz einfach:

    class Button
    {
    private:
      CallInterface* onClickAction;
    ///...
    public:
      void OnClickHandler(CallerInterface* call)
      {
        onClickAction=call;
      }
    ///...
      void receiveOnClickEvent() //auf Button wurde geclickt
      {
        if(call) //wurde handler gesetzt?
          call->call();
        else
          defaultAction(); //handle das Event defaultmaessig
      }
    };
    

    Du kannst dann einfach per:

    Button b;
    b.OnClickHandler(new Caller<whatever>(&w, &whatever::click));
    

    die Methode und das Objekt registrieren.
    whatever::click muss lediglich eine bestimmte Signatur haben, damit Caller sie aufrufen kann.

    Ich hatte angenommen das du mit CallInterface und call in receiveOnClickEvent() Call meintest... andernfalls könnte man ja kein Objekt vom Typ Caller darauf zuweisen

    Button b;
    b.OnClickHandler(new Caller<whatever>(&w, &whatever::click));
    

    Vielleicht stell ich mich dumm an aber ich verstehe immer noch nicht auf was der zeiger CallInterface* onClickAction zeigen soll ?
    Caller (bzw CallInterface) ist doch ein Template und muss erst ein Typen bekommen... 😕



  • Warum legt ihr Caller eigentlich auf dem Heap an? Hat das irgend einen tieferen Sinn?



  • z4Rilla schrieb:

    Vielleicht stell ich mich dumm an aber ich verstehe immer noch nicht auf was der zeiger CallInterface* onClickAction zeigen soll ?
    Caller (bzw CallInterface) ist doch ein Template und muss erst ein Typen bekommen... 😕

    Ich glaube, du hast Templates nur noch nicht verstanden...

    Caller ist ein Template - und dieses wird bei Caller<whatever>(...) instanziiert. dh das Template bekommt als Typen den Typ whatever zugewiesen.

    CallerInterface ist nichts anderes als eine abstrakte Basisklasse dazu. Caller<foo> und Caller<whatever> sind 2 unterschiedliche Typen. Um diese unterschiedlichen Typen gleich behandeln zu können, arbeiten wir mit Polymorphie. Hierbei wird CallerInterface zum Interface (die Schnittstelle um mit Caller<foo> und Caller<whatever> arbeiten zu können) Wenn wir CallerInterface->call() sagen, ruft der Compiler das richtige call (also entweder von Caller<whatever> oder Caller<foo>) auf.

    @jef:
    Wie würdest du es machen?
    In dem wir es auf dem Heap anlegen, können wir es gleich in ein CallerInterface umwandeln. Denn wir brauchen eine Referenz oder Zeiger, sonst klappt die Polymorphie nicht.

    Caller<whatever> c(&w, &whatever::action);
    foo.registerHandler(&c);
    

    würde natürlich auch gehen - aber da müssen wir höllisch aufpassen, dass c nicht aus seinem Scope gerissen wird. Denn dann wird es zerstört und foo hat einen Zeiger auf eine tote Instanz -> PENG



  • Entschuldigt die Threadaufwärmung, aber ich habe noch ein paar Fragen:

    Frage 1:
    Warum übergibt man dem b.OnClickHandler nicht einfach einen Funktionspointer?
    //EDIT
    Ich glaub ich weiß warum. In meinem "Alcatrazbeispiel" (http://www.c-plusplus.net/forum/viewtopic.php?t=96585), hab ich ja die Methode experiment::stopExperiment static machen müssen, damit ich sie meinem registrator übergeben kann. Dadurch musste ich auch die bool bRun static machen.
    Daraus folgt: Erzeuge ich mehrere Experimente, dann stimmt alles nicht mehr, da ja "bRun" static und damit instanzübergreifend ist.
    Richtigerweise müsste ich das mit so einem Caller lösen, oder?

    Frage 2: (Als Kommentare)
    [cpp]
    class CallBase
    {NOCOPY
    public:
    virtual void call()=0;
    };
    template<typename Class>
    class Call:public CallBase
    {
    public:
    typedef void (Class::Method)(); // Diese Zeile verstehe ich nicht.
    private:
    Class
    p;
    Method method; // Was ist Method für ein Typ?
    // Gibt's den erst duch das typedef?
    public:
    Call(Class* p, Method method)
    :p(p), method(method)
    {
    }
    void call()
    {
    (p->*method)();
    }
    };
    [/cpp]



  • typedef void (Class::*Method)();
    

    du kennst ja sicher funktionszeiger, oder? nunja, DAS ist ein typedef für einen methodenzeiger. sieht en bissl komisch aus, ist auch komisch zu benutzen, und wie du merken wirst, ist es noch schlimmer als es aussieht. 😉

    Method method;
    

    hier wird dann eine instanz des methodenzeigers erstellt, ein wirklich süßes teil.
    ist wahrscheinlich das am schwersten zu benutzende feature von c++, und im nachhinein muss ich sagen, dass ich ohne das wissen darüber besser klarkomme, als mit ihm.



  • ok, danke.
    Also einfach lieber nutzen als krampfhaft verstehen wollen.



  • hehejo schrieb:

    ok, danke.
    Also einfach lieber nutzen als krampfhaft verstehen wollen.

    Ich kann dir nur: http://www.function-pointer.org/ empfehlen.
    Lohnt sich das mal durchzulesen.

    Bei Methodenzeiger ist eigentlich nur die Syntax krank, die Logik ist recht simpel.



  • logic? bei methodenzeigern? in verbindung mit vererbung und base<->derived casting fängt der unfug doch schon an.



  • Shade Of Mine schrieb:

    Ich kann dir nur: http://www.function-pointer.org/ empfehlen.
    Lohnt sich das mal durchzulesen.

    Vielen Dank für den Link!
    Der hat mir einiges erleuchtet.


Anmelden zum Antworten