Propertys statt Getter und Setter Methoden?



  • Nabend,

    gibts es eigentlich ne Alternative zur Getter/Setter variante in C++ Klassen? Property wie in c# bspw.???

    Bei mehreren Paramter meientwegen 10, brauch ich alleine schon 20 Funktionen für die Get und Set methoden.

    int &Dummy::Property(){
     return m_i;
    }
    
    Dummy o;
    
    int k= o.Property();
    o.Property()= 6;
    

    wäre eine Mölichkeite, aber nich sehr Elegant.



  • zumal du bei deiner variante ein problem bekommst, wenn du die property eines const objektes auslesen möchtest.

    Zusätzlich bräuchtest du auch eine constvariante:

    const int &Dummy::Property()const{
     return m_i;
    }
    

  • Administrator

    1. Mit der Zeit geht das ganz schnell. Merkt man gar nicht mehr.
    2. 10 Parameter mit getter/setter? Das habe ich höchst selten. Du solltest vielleicht deine Klassen weiter aufspalten. Ok, am Ende hast du immer noch 10, aber auf mehr Klassen verteilt 😃
    3. Es gibt Hilfsmittel, z.B. von VAX Code Snippets. Die können einem die Arbeit erleichtern.
    4. Man könnte sowas auch mit Makros erledigen lassen, allerdings nicht wirklich schön:

    #define CLASS_MEMBER_GETTER_SETTER(membertype, membername) \
            membertype const& get_##membername##() const { return m_##membername##; } \
    	    void set_##membername##(##membertype const& membername##) { m_##membername = membername##; }
    

    Müsste natürlich noch ein wenig angepasst werden. Kommt drauf an, wie du deine Membervariablen benennst.
    5. Sonst ist mir nichts bekannt. Wie geht es denn in C#?

    Grüssli



  • Ich find die Makro-Idee eigentlich gar nicht so schlecht, da hab ich noch nie drüber nachgedacht!

    Mir geht das auch ziemlich auf die Nerven, wobei sich die G-/Settermethoden meist in Grenzen halten. Allerdings - jetzt nochmal alles neu implementieren? Nee...



  • Mit einigen (vielen?) IDEs kannst du auch automatisch standard-getter/setter generieren lassen.



  • Es gibt auch z.B. (nicht konforme!) Spracherweiterungen.



  • in C# gehts so:

    class MyClass
    {
    private int x;
    public int X
    {
    get
    {
    return x;
    }
    set
    {
    x = value;
    }
    }
    } 
    ...........
    MyClass p = new MyClass();
    
    p.X=6;
    
    int j = p.X;
    


  • PropertyUser schrieb:

    in C# gehts so:

    Da hast du ja in etwa den gleichen Schreibaufwand, wie in C++. 🙄

    Bei der Benutzung musst du hald die get() oder set(...) schreiben. Aber das ist ja kein Weltuntergang. 🙄



  • PropertyUser schrieb:

    in C# gehts so:

    Mit Einrückung wäre es deutlich lesbarer gewesen. Die Propertysyntax von C# reduziert aber nur dann den Schreibaufwand, wenn du die Standardimplementierung verwendest. Ich habe es noch nicht überprüft, aber scheinbar kann man unter C# 3.0 bei trivialen Getter/Setter die Implementierung weglassen:

    class MyClass
    {
      private int x;
      public int X { get; set; } // ka. ob Richtig, hatte es nur mal kurz überflogen
      //...
    }
    

    Properties halte ich nur aus einen Grund für sinnvoll: Das Sparen von "Get" und "Set", und den Zugriff in Form einer Elementsyntax. Es ist jedenfall (bei nichttrivialen Properties) nicht weniger Schreibaufwand.

    cu André



  • Und Properties erhöhen die Kapselung: Ich kann lesend oder schreibend auf eine Eigenschaft zugreifen, ohne wissen zu müssen, ob da jetzt im Hintergrund ein Methodenaufruf stattfindet oder nur eine einfache Zuweisung.
    Ist aber ein rein theoretischer Vorteil, praktisch gesehen bewirkt es aber zumindest, dass man sich bei boolschen Eigenschaften nicht zwischen getXXX(), isXXX() oder hasXXX() entscheiden muss 😉



  • Chewie83 schrieb:

    ...bewirkt es aber zumindest, dass man sich bei boolschen Eigenschaften nicht zwischen getXXX(), isXXX() oder hasXXX() entscheiden muss 😉

    Um genau zu sein verwendet C# intern auch nur Getter und Setter, ich glaube get_xxx und set_xxx.

    cu André



  • Properties reduzieren den Schreibaufwand clientseitig (minimal).

    Library-seitig erhöhen sie manchmal den Schreibaufwand ordentlich. Nämlich dann wenn man alles als Property abbildet was "eine Property sein sollte", und dazu dann diverse Hilfklassen basteln muss (z.B. Collection-Klassen die mit der "Parent-Klasse" kommunizieren).



  • Wobei ich auch schon oft darüber nachgedacht habe, Getter und Setter durch ne Fkt zu ersetzen, die ne (const) ref wiedergibt...

    class Name
    {
    private:
      std::string m_vorname;
      std::string m_nachname;
    public:
    //...ctor...
      std::string& Vorname () {return m_vorname;}
      const std::string& Vorname () const {return m_vorname;}
    };
    

    Ist zwar der gleiche Schreibaufwand, aber hat den Vorteil, dass so etwas besser möglich ist:

    int main ()
    {
    Name name ("vorname", "nachname");
    name.Vorname () += " 2.Vorname";
    }
    

    bb



  • Aber wo bleibt da der Vorteil gegenüber public -Membern? Einheitliche Schnittstelle und Klammersyntax?

    Die Gefahr hierbei ist ja wieder, dass man z.B. durch Seiteneffekte ungewollt die Member verändert, wenn man aber eigentlich nur lesen will...


  • Administrator

    @unskilled,
    Aber sowas ist eher selten. Meistens gibt man dem User zuerst den ganzen String zurück in ein Edit-Feld oder ähnliches und der User verändert den String dann. Am Ende speichert man sowieso wieder den ganzen String.
    Dass es tatsächlich mal ein append gibt, ist bei mir äusserst selten und wenn es einen gibt, dann habe ich meistens eine append_xxx Funktion drin.

    Grüssli



  • unskilled schrieb:

    Ist zwar der gleiche Schreibaufwand, aber hat den Vorteil, dass so etwas besser möglich ist:

    Und den wesentlichen Nachteil das der Code anders als gewohnt, und damit schwerer zu lesen ist. Zudem wird die konstante Referenz nur bei Konstanten Objekt verwendet, die Kapselung zerstört (Jeder kann sich die Referenz merken und beliebig manipulieren...



  • asc schrieb:

    unskilled schrieb:

    Ist zwar der gleiche Schreibaufwand, aber hat den Vorteil, dass so etwas besser möglich ist:

    Und den wesentlichen Nachteil das der Code anders als gewohnt, und damit schwerer zu lesen ist. Zudem wird die konstante Referenz nur bei Konstanten Objekt verwendet, die Kapselung zerstört (Jeder kann sich die Referenz merken und beliebig manipulieren...

    Japp - war erstens noch nen eher unpassendes Beispiel und zweitens hab ich ja auch geschrieben, dass ich es mir immer nur überlegt habe und dann doch jedes mal wieder verworfen habe ^^

    asc schrieb:

    die konstante Referenz nur bei Konstanten Objekt verwendet

    Oo das hab ich noch gar nicht gewusst - dachte bisher eigtl immer, dass der compiler immer versucht, const zu nehmen und erst, wenn er das nicht kann, nimmt er die "normale" fkt?!

    bb



  • Ja eben, ich frage mich wieso man die members nicht einfach öffentlich macht, wenn sie via Get/Set verändert werden dürfen. Ist wohl schlechter Stil? Macht das legendäre Information-Hiding Konzept kaputt!?

    Wäre edel, wenn man member nich nur public/private anlegen könnte, sonder auch ReadOnly, WriteOnly ... und sich so das Get/Set Information Hiding konzept schenkt^^



  • PropertyUser schrieb:

    Ja eben, ich frage mich wieso man die members nicht einfach öffentlich macht, wenn sie via Get/Set verändert werden dürfen. Ist wohl schlechter Stil? Macht das legendäre Information-Hiding Konzept kaputt!?

    Ja, ist schlechter Stil. Der Grund ist dafür das öffentliche Member unkontrolliert manipuliert werden können, man keine Änderungen der Freigabe mehr vornehmen kann ohne die Schnittstelle zu ändern, und auch jegliche Bereichsprüfungen unmöglich werden.

    Nehmen wir mal an du machst folgendes:

    class Adresse {
        public:
            std::string name;
            std::string nachname;
    };
    
    int main()
    {
        Adresse paul;
        paul.name = "Paul";
        paul.name = "Zufall";
    }
    

    Dann kann jeder diese Werte unkontrolliert ändern, und nicht nur das, man kann sich Referenzen auf diese Werte merken, sie speichern und jegliches Geheimnisprinzip wird vernichtet. Gehen wir einen Schritt weiter:

    class Adresse {
        private:
            std::string name;
            std::string nachname;
        public:
            std::string GetName() const { return name; }
            void SetName(std::string const & name) { this->name=name; }
            std::string GetNachname() const { return nachname; }
            void SetNachname(std::string const & nachname) { this->nachname=nachname; }
    };
    

    Im ersten Moment mag dies für dich identisch erscheinen. Aber bereits jetzt gibt es ein paar gravierende Änderungen: Man kann keine Referenz auf die Member mehr anlegen, direkte und unkontrollierte Änderung ist nicht möglich.

    Weiterer Vorteil: Man kann Bereichsprüfungen einbauen ohne die Schnittstelle zu ändern; man kann Die Daten in ein anderes Objekt verschieben und die Klasse durch Delegation dennoch lauffähig halten; man kann den Zugriffsschutz separat für Getter und Setter anpassen.

    PropertyUser schrieb:

    Wäre edel, wenn man member nich nur public/private anlegen könnte, sonder auch ReadOnly, WriteOnly ... und sich so das Get/Set Information Hiding konzept schenkt^^

    ReadOnly: Konstante
    WriteOnly: Zumeist (aber nicht immer) ein Designfehler
    Und Referenzen wären dann dennoch möglich.

    In sofern sind die Properties in C# 3.0 oder C++/CLI doch schon schön: man kann erst einmal die Properties als triviales get/set (ohne weiteren Code) deklarieren und später anpassen.

    Ergo: Bitte unter C++ keine öffentlichen Member verwenden, du verhinderst damit die Codewartung (und ja, es gibt Unterschiede zwischen trivialen Properties bzw. get/set und direkten Memberzugriff).

    cu André
    P.S: Ich durfte die Nachteile öffentlicher Methoden, und Zeiger auf die Member in einem Projekt schon ausbaden, da der vorherige Programmierer an Schreibfaulheit leided.



  • asc schrieb:

    PropertyUser schrieb:

    in C# gehts so:

    [...]

    class MyClass
    {
      private int x;
      public int X { get; set; } // ka. ob Richtig, hatte es nur mal kurz überflogen
      //...
    }
    

    [...]

    Nur kurz eine kleine Korrektur, so sähe das aus:

    class MyClass {
      public int X { /*private*/ get; /*private*/ set; }
      /...
    }
    

    Der Compiler generiert das private Feld selbstständig im Hintergrund. AFAIR ab C# 3.5.



  • SolidOffline schrieb:

    AFAIR ab C# 3.5.

    Ahh... erst in der Zukunft? 😉
    Derzeit aktuell .Net Framework 3.5 und C# 3.0...


Anmelden zum Antworten