Zugriffsfunktion von Klasse - Sinnvoll?



  • Hi,
    Was ist eigentlich "richtiger", innerhalb einer Klasse auch deren Getter/Setter Funktionen nutzen oder direkt auf die member Variablen zugreifen?
    Oder möglicherweise auf Getter/Setter komplett verzichten?
    Sollte man sowas dann von Fall zu Fall neu entscheiden oder zu Gunsten einer einheitlichen Programmierung das einmal Festlegen?

    Ich sage mal, wenn die Getter/Setter Funktion nichts an der Variable ändern die sind sie ja unnötiger Code, was die Klasse groß macht und das Programm langsamer (ein normaler Funktionsaufruf mit Parametern sind ja um die 7 Assemblerbefehle)? Dann könnte ich mir Setter/Getter komplett sparen.

    Bei Funktionen, die die Variable vielleicht noch manipulieren würde das dann mehr Sinn machen, sowohl für den Aufruf innerhalb, als auch außerhalb der Klasse.
    Hab während meiner Google Streifzüge auch einige Artikel gefunden wo viele mittlerweile ganz gegen Getter/Setter sind, wenn diese wirklich nichts an der Variable ändern.

    Wie denkt ihr darüber?



  • Meiner Meinung nach sind getter und setter keine schlechte Idee. Wird auf die Membervariable jedoch oft zugegriffen, dann sollte der direktzugriff ermöglicht werden. Alternativ kann man sich natürlich Zeiger zurückgeben lassen. Was "richtiger" ist, ist glaub ich ziemlich subjektiv...



  • Getter und Setter kosten nichts an Performance (Stichwort: Inlining) und bringen zumindest etwas Abstraktion. Der Sinn und Zweck von S/Gettern, die gar nichts machen, mag zwar zunächst fraglich sein. Aber sobald man nur eine simple Überprüfung machen möchte (z.B. > 0), wird der Unterschied deutlich:
    S/Getter implementiert: Eine Überprüfung einbauen.
    S/Getter nicht implementiert: hunderte Prüfungen einbauen, zehn vergessen.
    Jetzt will man noch eine Überprüfung einbauen (z.B. <= 100)
    S/Getter implementiert: Eine Überprüfung einbauen.
    S/Getter nicht implementiert: hunderte Prüfungen einbauen, zehn vergessen.
    ...

    Das Problem sollte klar sein. Zudem kommt es auch oft dazu, dass man S/Getter hat, die gar keine Membervariable haben. Eine Uhr kann die interne Zeit in Sekunden speichern. Was macht dann aber eine getMinute()-Methode?

    Viel wichtiger ist eher die Frage, ob man überhaupt simple S/Getter braucht. Schließlich brechen sie irgendwie die Kapselung. Aber sie sind in _jedem_ Fall besser als Zeiger auf Membervariablen zurückzugeben oder diese public zu machen.

    Ausnahmen sind "Datenpakete", Plain-Old-Data-Structs, deren Interface die Daten selbst sind.

    P.S.: "in _jedem_ Fall", "Ausnahmen sind...", 😉

    Gruß
    Don06



  • Ich hab mich schon länger dran gewohnt getter und setter zu verwenden. So richtig darüber nachgedacht habe ich nie. Irgendein Instinkt sagte mir dass es so besser ist 😃 . Eine Frage hätte ich da aber - was ist wenn die klasse abstrakt ist? Was stellt der Compiler an, wenn eine rein virtuelle methode als inline definiert wird.



  • In den meisten Fällen würde ich euch sofort zustimmen, aber gerade bei der Handhabung interner Klassenfunktionen finde ich setter/getter doch irgendwie unübersichtlich:
    Als Beispiel mal ein Vektor, weil dieser irgendwie prädestiniert dafür ist 😉

    class Vektor {
    private: double x,y,z;
    public:
        void SetX(double pX) { x = pX);
        double GetX() const { return x);
        //usw.
        void AddVektor(const Vektor &pVektor) {
          //Variante 1
          SetX(GetX() + pVektor.GetX());
          //Variante 2
          x += pVektor.x; // kürzer und übersichtlicher als Variante 1
          //usw.
        }
    };
    


  • @Pille: Intern kann man natürlich auch direkt auf Member zugreifen. Das sollte klar sein. Memberfunktionen dürfen ja intern z.B. auch Invarianten verletzen, solange nachher wieder ein brauchbarer Status hergestellt wird. Teilweise kann man dann Getter und Setter intern gar nicht benutzen, da sie die Verletzung der Invarianten bemerken und das irgendwie mitteilen würden (z.B. Assetion failed, throw Exception).

    Gruß
    Don06



  • Pille456 schrieb:

    Was ist eigentlich "richtiger", innerhalb einer Klasse auch deren Getter/Setter Funktionen nutzen oder direkt auf die member Variablen zugreifen?
    Oder möglicherweise auf Getter/Setter komplett verzichten?

    Getter/Setter sind besser als public Member.

    Getter ohne Setter sind noch besser. Die Initialisierung eines Objekts sollte im Konstruktor geschehen.

    Eine Klasse die ohne Getter und Setter auskommt ist noch besser. Allerdings muss dann die Umgebung auch entsprechend 'designed' sein.

    Pille456 schrieb:

    Als Beispiel mal ein Vektor, weil dieser irgendwie prädestiniert dafür ist 😉

    class Vektor {
    private: double x,y,z;
    public:
        void SetX(double pX) { x = pX);
        double GetX() const { return x);
        //usw.
        void AddVektor(const Vektor &pVektor) {
          //Variante 1
          SetX(GetX() + pVektor.GetX());
          //Variante 2
          x += pVektor.x; // kürzer und übersichtlicher als Variante 1
          //usw.
        }
    };
    

    Lese Dir mal diesen Thread zum Vektor und dies hier zu den Settern durch.

    Gruß
    Werner



  • Das mit dem Vektor war wirklich nur ein Beispiel, aber danke für die Klasse, könnte mir helfen.. 😃
    Die Diskussion in dem Thread über Designfehler oder nicht und die Verwendung von Getter/Setter war zwar recht interessant, aber irgendwie hat sie mir nicht wirklich weitergeholfen.

    Vielleicht wurde mir das aus dem Thread noch nicht ganz klar, aber was tust du wenn:
    Wenn du eine einzelne Koordinate eines Vektors ändern möchtest? (Weil z.B der Benutzer den Vektor in einem mathematischen Programm entlang der X-Achse verschoben hat)
    Ein komplett neuen Vektor erschaffen? Oder alle Koordinaten des Vektors setzen? (Käme das nicht auf dasselbe heraus wie drei separate Setter?)

    Tut mir Leid wenn ich gerade total aufm Schlauch stehe (so komme ich mir nämlich gerade vor), aber ich habe auf meine oben beschriebene Frage immer noch keine Antwort, ob man innerhalb einer Klasse Setter/Getter nutzen soll.
    Als einziges Pro Argument fällt mir wirklich nur ein, dass man durch die Setter/Getter eine einheitliche Schnittstelle nach außen hat und gegebenenfalls noch etwas an den Variablen manipulieren kann.
    Beim Beispiel des Vektors fällt mir zwar partout kein Beispiel ein, wenn man sinnvoll was manipulieren will.... aber wer weiß 😉



  • In gewisser Weise hast du Recht. Du ziehst nur nicht die richtigen Schlüsse ;). Du brauchst eventuell keine Getter oder Setter, aber dann brauchst du auch keinen direkten Zugriff auf die Member-Variablen. Eine Verschiebung auf der x-Achse über eine setX()-Methode bedürfte imho eines Kommentars, da nicht direkt ersichtlich ist, dass es sich um eine Verschiebung handeln soll. Eine Verschiebung lässt sich über eine Vektoraddition beschreiben und so sollte sie auch implementiert sein, auch, wenn man nur auf einer Achse verschiebt.

    Vector pos(2, 3);
    const Vector dir(1, 0);
    pos += dir;
    

    Zu den internen Daten: Was passiert, wenn du jetzt aus Geschwindigkeitsgründen eine fertige Vektorimplementierung verwendest (z.B. DirectX, OpenGL, keine Ahnung wie die das implementieren), die _keinen_ direkten Zugriff auf die Member erlaubt, sondern alles über Funktionen regelt. Spätestens dann bricht ein Interface, dass direkten Zugriff auf die Member verspricht zusammen. Das mag bei einer so simplen Klasse wie einem Vektor, der intern nunmal meist aus 2 bis 3 floats/doubles besteht, noch relativ unwahrscheinlich sein. Aber bis jetzt spricht alles für Getter/Setter und gegen direkt Zugriff. Wie Werrner noch einmal klar gemacht hat, ist die optimale Lösung auch ohne Getter/Setter auszukommen.

    Überlege dir, ob das "Feature" einzelne Elemente eines Vektors neu zu setzen, tatsächlich nötig ist. Überlege dir ein Szenario, in der ein Benutzer genau das "Feature" braucht und auch sinnvoll verwenden kann, d.h. es keine andere Möglichkeit gibt, es anders und genausogut zu lösen. Es kann wirklich vorkommen, dass man so primitive Sachen wie Getter/Setter benötigt, oft auch, wie Werner bereits sagte, weil die Umgebung sonst ein komplettes Redesign bräuchte. In solchen Fälle hat man dann (aus Zeitgründen) keine andere Wahl und nimmt das schlechtere Design hin.

    P.S.: Ein Vektor lässt sich auch als Betrag(Länge) und Richtung darstellen. Auch wenn das üblicherweise nicht so implementiert wird 😉

    Gruß
    Don06



  • Ah okay, es dämmert langsam!
    Dankeschön!


Anmelden zum Antworten