Pointer oder Referenzen bei Übergabeparameter?



  • Cosmixx schrieb:

    1310-Logik schrieb:

    Eine "gute" Funktion/Methode sollte nicht einen Übergabeparameter verändern dürfen. Ergebnisse sollten nur mit return zurückgegeben werden.

    Das halte ich für nicht konsequent umsetzbar. Was machst Du, wenn eine Methode mehrere Parameter ändern muss?

    Ein Tupel zurückgeben. Gut, in C++ ist das mit einer nicht sehr schönen Syntax verbunden. In anderen Sprachen (wohl hauptsächlich funktionalen) ist es aber gang und gäbe.



  • 1310-Logik schrieb:

    Wo ich keinen Weg mit Referenzen sehe: bei der Behandlung polymorpher Objekte

    😕

    Nochmal zur Erinnerung, zum Speichern sind Referenzen sowieso nicht gemacht.



  • .filmor schrieb:

    1310-Logik schrieb:

    Wo ich keinen Weg mit Referenzen sehe: bei der Behandlung polymorpher Objekte

    😕

    Nochmal zur Erinnerung, zum Speichern sind Referenzen sowieso nicht gemacht.

    Ich meinte zB beim Observer Pattern. Wie willst du da ne Referenz übergeben?

    virtual void update( Subject* subject )
    {
        Foo* foo = dynamic_cast< Foo* >( subject );  //Foo ist abgeleitet von Subject (Abstrakte Klasse)
        foo->doBar();
    }
    


  • Mit dem dynamic_cast setzt du dich ja auch eigentlich über das Konzept der Polymorphie hinweg, normale virtuelle Methoden funktionieren mit Referenzen ohne Probleme.

    Btw, so gehts auch mit Referenzen:

    virtual void update( Subject& subject )
    {
        Foo* foo = dynamic_cast< Foo* >( &subject );
        foo->doBar();
    }
    

    😉



  • Ja, aber doBar() ist eine Methode von Foo, nicht von Subject, also muss ich ja casten.
    So sieht doch die "offizielle" Implementierung vom Observer aus?
    Warum denn nun Referenzen?



  • [edit] war Blödsinn [/edit]

    Greetz, Swordfish



  • 1310-Logik schrieb:

    Ja, aber doBar() ist eine Methode von Foo, nicht von Subject, also muss ich ja casten.
    So sieht doch die "offizielle" Implementierung vom Observer aus?

    virtual void update( Subject* subject )
    {
        Foo* foo = dynamic_cast< Foo* >( subject );  //Foo ist abgeleitet von Subject (Abstrakte Klasse)
        foo->doBar();
    }
    

    Was ist denn das für eine Implementierung des Observer-Patterns?
    Wenn Du in der update-Methode ein Subject als Pointer übergibst, kannst Du den doch nicht in der Methode pauschal zu einem Typ einer abgeleiteten Klasse casten.





  • Ah, ok, wenn Du das als Beispiel nimmst, dann ist klar. Gefällt mir aber designtechnisch nicht.



  • Cosmixx schrieb:

    Das halte ich für nicht konsequent umsetzbar. Was machst Du, wenn eine Methode mehrere Parameter ändern muss?

    diesen designfehler jagen, ihn umzingeln und vernichten natürlich.



  • volkard schrieb:

    diesen designfehler jagen, ihn umzingeln und vernichten natürlich.

    😃 Na das will mich mal sehen in einem realen Projekt.

    Ich habe nicht gesagt, dass es ein Designfehler ist, falls Du das mit dem auffallend fett gedrucktem Wort sagen willst ;). Mir gefällt es nur nicht.
    Das Beispiel ist in jedem Fall eine gängige Observer-Pattern-Implementierung. Trotzdem kann man das mit dem Casten in einen abgeleiteten Typ vermeiden.
    Btw, nicht bei jeder Observer-Implementierung muss man den this-Pointer des Subjekts weitergeben oder?



  • Cosmixx schrieb:

    Das Beispiel ist in jedem Fall eine gängige Observer-Pattern-Implementierung. Trotzdem kann man das mit dem Casten in einen abgeleiteten Typ vermeiden.

    Wie würdest Dus im Getreide Beispiel lösen?

    Cosmixx schrieb:

    Btw, nicht bei jeder Observer-Implementierung muss man den this-Pointer des Subjekts weitergeben oder?

    Wenn Du mehrere Subjekte beobachtest, und wissen willst, von welchem die Nachricht ist, dann schon.



  • Seit wann kann man mit dynamic_cast keine Referenzen casten ??

    virtual void update( Subject& subject ) 
    { 
        Foo& foo = dynamic_cast< Foo& >( subject );  //Foo ist abgeleitet von Subject (Abstrakte Klasse) 
        foo.doBar(); 
    }
    


  • Hat mich auch schon gewundert dass das keiner einwendet 😉

    Dabei weiss doch jeder, dass ein dynamic_cast auf Referenzen einen bad_cast werfen kann, während der auf Pointern einen Nullzeiger zurückliefert, wenn's nicht stimmt 🤡



  • Cosmixx schrieb:

    volkard schrieb:

    diesen designfehler jagen, ihn umzingeln und vernichten natürlich.

    Ich habe nicht gesagt, dass es ein Designfehler ist

    aber ich. zeig mir mal ne anwendung für wo zwei returnwerte benötig werden. ich müßte lange in der krimskramskiste suchen.



  • 1310-Logik schrieb:

    Wenn Du mehrere Subjekte beobachtest, und wissen willst, von welchem die Nachricht ist, dann schon.

    Das ist mir bewusst. Man kann das Casten aber auch vermeiden, durch eine Art Objekt-ID, die über eine virtuelle Methode abgerufen wird oder über RTTI.

    Die Referenz auf das Subjekt ist außerdem hinfällig, wenn man dieses nicht zum updaten braucht, z.B. wenn die Daten von ganz woanders herkommen, im einfachsten Fall aus einer Singleton-Datenklasse.

    1310-Logik schrieb:

    Wie würdest Dus im Getreide Beispiel lösen?

    Man sollte zumindest in der update-Methode überprüfen, ob der dynamic_cast erfolgreich war. Wobei wir wieder beim Ausgangsthema wären: Wenn man nämlich das Subjekt als Pointer übergibt, liefert dynamic_cast NULL zurück und bei einer Referenz wird eine Exception geworfen.

    Für das kleine Beispiel, dass der Veranschaulichung dient, ist es aber ok so.

    volkard schrieb:

    zeig mir mal ne anwendung für wo zwei returnwerte benötig werden. ich müßte lange in der krimskramskiste suchen.

    Achso das meinst Du. Es ging doch darum, dass eine Anwendung keinen Übergabeparameter ändern sollte und Ergebnisse nur über return zurückgeben sollte. IMHO kann man das nicht durchziehen. Ich hab hier grade einen Nachrichtengenerator für Nachrichten, die über Sockets versendet werden. An die übergebe ich nen BYTE-Pointer, der mit dem Inhalt der Nachricht gefüllt wird und einen integer, der die Länge der Nachricht erhält. Sind schonmal 2 Parameter.



  • warum bekommste keine

    struct message
    { 
      BYTE * msg;
      size_t length;
    };
    

    zurück?

    Oder gar ne class mit sinnvollen Operationen?



  • typedef std::pair< BYTE*, int > ReturnvalueType;
    

    ??

    Mit dem überprüfen haste recht, währ besser mit reference.
    das mit dem rtti hab ich nicht geschnallt.. 😕



  • Cosmixx schrieb:

    IMHO kann man das nicht durchziehen.

    dem stimme ich zu. aber die ausnahmen sind selten und werden immer seltener.

    Ich hab hier grade einen Nachrichtengenerator für Nachrichten, die über Sockets versendet werden. An die übergebe ich nen BYTE-Pointer, der mit dem Inhalt der Nachricht gefüllt wird und einen integer, der die Länge der Nachricht erhält. Sind schonmal 2 Parameter.

    also hätten die auch nen std::string zurückgeben können.



  • volkard schrieb:

    Cosmixx schrieb:

    IMHO kann man das nicht durchziehen.

    dem stimme ich zu. aber die ausnahmen sind selten und werden immer seltener.

    Ich hab hier grade einen Nachrichtengenerator für Nachrichten, die über Sockets versendet werden. An die übergebe ich nen BYTE-Pointer, der mit dem Inhalt der Nachricht gefüllt wird und einen integer, der die Länge der Nachricht erhält. Sind schonmal 2 Parameter.

    also hätten die auch nen std::string zurückgeben können.

    Auf das gleiche "Problem" bin ich neulich auch gestoßen, als es darum ging Dateien aus einem Archiv auszulesen.
    Hab dann ganz einfach zwei Funktionen erstellt, eine die einen Speicherbereich und dessen Größe als Parameter erhält und eine die einen std::vector zurückgibt. Letztere ist mit Hilfe ersterer implementiert.
    So hat der Benutzer die Möglichkeit die Speicherallokation zu beeinflussen, oder wenn es ihm egal ist eine einfachere Methode zu verwenden.


Anmelden zum Antworten