Konstruktor-Initialisierung



  • du hast eine klasse weltraumschiff, die eine eigenschaft "geschwindigkeit (int)" besitzt. du kannst beschleunigen und abbremsen (geschw. erhöhen und vermindern)

    1. du deklarierst geschwindigkeit im public bereich.
      jedesmal, wenn du die geschw. erhöhen willst, schreibst du instanz.geschw + 2;
      jetzt merkst du aber, es ist dir zu langsam. du willst lieber + 4. schreibst du jetzt überall + 4 statt + 2? ist das keine tipparbeit?

    2. du machst sie private und definierst beschleunigen() und abbremsen() (vereinfacht):

    void weltraumschiff::beschleunigen () { geschwindigkeit += 4; }
    void weltraumschiff::abbremsen () { geschwindigkeit -= 4; }
    

    jetzt musst du nur die funktionen ändern, wenn du das verhalten der klasse im ganzen projekt ändern willst.

    deshalb kann es auch sinn machen, innerhalb einer klasse immer die passenden "Getter" und "Setter" einzusetzen, wenn es auch nicht immer direkt "Getter" und "Setter" sind.

    was ich sagen will: bei einem bug hast du den fehler einfach leichter einzugrenzen



  • Ich hab in meinem Kleinen Stretegiespiel zur Zeit 20-30 Klassen. Die alle mit Settern und Gettern auszustatten würde
    a) unmenge an Zeit annehmen.
    b) ich kapsel lieber die Klassen in eine MainKlasse und lasse nur die Mainklasse auf verschiedene Elemente zugreifen (machen elemente kann noch nicht mal die MainKlasse direkt benutzen!!!)
    Aber ALLE vars in Klassen mit Settern und Gettern auszustatten ist meiner Meinung nach unsinn...

    Und ich schreibe privat ein GUI-Framework für Windows mit mehr als 250 Klassen, wo auf *alle* Variablen mit Gettern und Settern zugegriffen wird.

    Beruflich sind es bestimmt fünfmal soviele (schwer zu schätzen). Das alte Zeugs ist gut sieben Jahre alt, da hat man sich schonmal die eine oder andere Schlampigkeit geleistet. Und dann kam Y2K, und dann kam der Euro.... Und die Jungs, die diesen Mist verbrochen hatten, waren längst woanders. Ich kann dir nur sagen: Wir hatten richtig Spaß!

    Mir ist das nicht zuviel Arbeit. Ich habe einfach am eigenen Leib erlebt, wozu Kapselung gut ist.

    Stefan.



  • Original erstellt von davie:
    **du hast eine klasse weltraumschiff, die eine eigenschaft "geschwindigkeit (int)" besitzt. du kannst beschleunigen und abbremsen (geschw. erhöhen und vermindern)

    1. du deklarierst geschwindigkeit im public bereich.
      jedesmal, wenn du die geschw. erhöhen willst, schreibst du instanz.geschw + 2;
      jetzt merkst du aber, es ist dir zu langsam. du willst lieber + 4. schreibst du jetzt überall + 4 statt + 2? ist das keine tipparbeit?

    2. du machst sie private und definierst beschleunigen() und abbremsen() (vereinfacht):

    void weltraumschiff::beschleunigen () { geschwindigkeit += 4; }
    void weltraumschiff::abbremsen () { geschwindigkeit -= 4; }
    

    jetzt musst du nur die funktionen ändern, wenn du das verhalten der klasse im ganzen projekt ändern willst.

    deshalb kann es auch sinn machen, innerhalb einer klasse immer die passenden "Getter" und "Setter" einzusetzen, wenn es auch nicht immer direkt "Getter" und "Setter" sind.

    was ich sagen will: bei einem bug hast du den fehler einfach leichter einzugrenzen**

    Bei solchen sachen ist es ja klar.
    Aber nehmen wir mal an du hast die BaseClass ship mit den member speed und den settern und gettern. Wenn du speed als protected deklarierst kannst du diese member automatisch an die nächsten Raumschiffe weitergeben (Freighter, Warship etc..)
    Wenn du speed als private deklarierst werden sie aber NICHT an die abgeleiteten Klassen weitergegeben!
    Und ich benutze schon Setter und Gettern. Aber bei manchen Speicher-Klassen, hab ich lieber direkten zugriff auf die Member da, diese Klassen sowieso NUR von einer MainKlasse aus gesteuert werden.
    Zum beispiel die Klasse sSprite bei mir

    class sSprite
    {
    public:
       sSprite()
       {
          next=prev=NULL;
       }
       ~sSprite()
       {
          next=prev=NULL;
          delete Image;
       }
    ...
    };
    

    die sSprite klasse wird nur von der Klasse cGrafik benutzt die Sprites, laden und anzeigen kann. Andere Klassen haben keinen Zugriff auf cGrafik sondern nur auf die Funktionen ShowSprite(char *Name); und LoadSprite(char *Name);
    Deshalb halte ich zu internsives OOP für zu übertrieben!



  • Original erstellt von <StefanD>:
    **Und ich schreibe privat ein GUI-Framework für Windows mit mehr als 250 Klassen, wo auf *alle* Variablen mit Gettern und Settern zugegriffen wird.

    Beruflich sind es bestimmt fünfmal soviele (schwer zu schätzen). Das alte Zeugs ist gut sieben Jahre alt, da hat man sich schonmal die eine oder andere Schlampigkeit geleistet. Und dann kam Y2K, und dann kam der Euro.... Und die Jungs, die diesen Mist verbrochen hatten, waren längst woanders. Ich kann dir nur sagen: Wir hatten richtig Spaß!

    Mir ist das nicht zuviel Arbeit. Ich habe einfach am eigenen Leib erlebt, wozu Kapselung gut ist.

    Stefan.**

    Hab einen Post weiter oben ein Beispiel gepostet.
    Klar ist Kapselung wichtig. Aber wenn die Klasse nur von EINER Kontrollklasse verwendet wird, ist es doch relativ wurscht ob man direkt auf die Vars zugreift oder setter und getter einbaut.

    Für Klassen auf die mehrere Objekte zugreifen (sagen wir mal eine Globale Klasse) wird natürlich nicht für alle zugänglich gemacht!
    Sonst würde ja in meinem Beispiel dauernd jemand (wenn ich Pech hab) die Zeiger auf NULL setzten oder sonst wie verlinken!



  • du benutzt die struktur also nur zum datenspeichern. pass aber auf, dass du dir selbst nicht reinpfuschst. auch nach 2 jahren pause nicht.

    zu deinem beispiel:
    wenn ich speed private mache, können die abgeleiteten klassen speed nicht verändern, aber über die getter und setter methoden schon. wo ist das problem?
    eine fremde klasse könnte hier dann ohne spezielle getter/setter sehr gut herumpfuschen.



  • Original erstellt von davie:
    **du benutzt die struktur also nur zum datenspeichern. pass aber auf, dass du dir selbst nicht reinpfuschst. auch nach 2 jahren pause nicht.

    zu deinem beispiel:
    wenn ich speed private mache, können die abgeleiteten klassen speed nicht verändern, aber über die getter und setter methoden schon. wo ist das problem?
    eine fremde klasse könnte hier dann ohne spezielle getter/setter sehr gut herumpfuschen.**

    Ok, dann werden also Base Private member an "kinder" weiter abgeleitet aber sie können nicht darauf zugreifen!
    Praktisch so einer art versteckte Variable!
    Aber was ist wenn ein Freighter mit Faktor 2 fliegt und das Warship mit Faktor 4?? Was wäre dann dein Vorschlag?



  • Hi

    Huhu. Es war nur ein Beispiel. Ich machs jetz mal wie die Grashalme im Wind und beuge mich. Ok. Datenkapselung über alles. Ich werde mich bessern versprochen. 😉



  • void beschleunige (double faktor) { speed*=faktor; }

    zum beispiel. kommt halt drauf an, was du willst. willst du das verhalten von beschleunigen/abbremsen den kind-klassen überlassen, wäre polymorphie vielleicht auch passend.



  • wie wäre es mit einer protected const float SpeedFactor; die mit dem Konstruktor initialisiert wird!
    Wäre vielleicht eine annehmbare Lösung oder?



  • Einige Leute (z.B. Herr Fowler, wenn ich mich nicht irre) plädieren sogar mit ziemlich guten Gründen dafür, selbst in der Klasse, der die Variablen gehören, ausschließlich per Methode darauf zuzugreifen.

    @Stefan D.
    Nein der Herr Fowler war es nicht (vgl. "Refactoring - Improving the design of existing code" Seite 170f:). Abgeneigt ist er allerdings auch nicht.

    Ansonsten stimme ich StefanD zu. Instanz-Variablen sollten private sein. Nicht protected. Und zwar nicht protected aus *exakt* dem selben Grund warum sie nicht private sein sollten. Ein nicht private Instanzvariable liegt *außerhalb* der Kontrolle des Klassenbauers. Es kann potentiell unendlich viel Code existieren der von dieser Variablen *abhängig* ist. Wird die Variable geändert oder entfernt, so kann potentiell unendlich viel Code dabei kaputt gehen. Code der nicht im Verantwortungsbereich des Klassenbauers liegt. Damit kann letztlich kaum noch eine Änderung durchgeführt werden.

    Man hat letztlich *exakt* die selhen Abhängigkeiten wie bei public Instanzvariablen.

    Das gilt natürlich alles nicht für Leute die immer nur für sich allein in einem Ein-Mann-Unternehmen entwickeln bzw. die immer allen Code besitzen. Nur auf wen trifft sowas zu?

    [ Dieser Beitrag wurde am 27.06.2003 um 00:50 Uhr von HumeSikkins editiert. ]



  • Original erstellt von stealth00:
    Aber wenn die Klasse nur von EINER Kontrollklasse verwendet wird, ist es doch relativ wurscht ob man direkt auf die Vars zugreift oder setter und getter einbaut.

    na dann waere eine struct wohl besser - nur offene daten...
    halt moment mal!
    was wenn wir wollen dass diese Klasse ihr verhalten aendert? So soll die Variable brueckenoffiziere nie mehr als 12 sein duerfen (weil mehr als 12 nicht auf die bruecken passen) - was machst du dann?

    Oder wenn du eine neue Variable hinzufuegst: LeuteAufBruecke - welche von brueckenoffiziere abhaengig ist (nur dass uU noch besucher dazu kommen koennen).

    Dann musst du LeuteAufBruecke ja updaten wenn ein brueckenoffizier mal schnell nen kaffee trinken geht (nur leider geht das nicht, denn irgendwo im code steht dann ja:

    raumschiff.brueckenoffiziere-=2;
    anstatt
    raumschiff.BrueckenoffizierLeave();
    raumschiff.BrueckenoffizierLeave();
    oder aehnliches.

    obwohl deine klasse nur von einer anderen verwendbar ist, so ist sie doch eigenstaendig, oder?

    Dein Beispiel mit den Raumschiffen:
    was ist besser:
    //increment speed by 2 steps
    Raumschiff.speed+= (2*SPEED_KONSTANTE_FUER_DIESES_RAUMSCHIFF);
    //denn du bist spaeter drauf gekommen dass raumschiffe eine verschiedene step weite haben...
    oder
    Raumschiff.faster(2);

    faster koennte virtual sein und jedes raumschiff weiss wie gross so ein schritt ist.

    dabei bleibt speed private in BaseShip, denn es gibt in BaseShip ja ne protected methode: incrementSpeed()
    und faster sieht so aus:

    virtual void faster(int step)
    {
    incrementSpeed(step*SPEED_KONSTANTE);
    }

    und incrementSpeed sieht dann so aus:

    void incrementSpeed(double inc)
    {
    if(speed+inc > MAXIMAL_WERT)
    throw "wir sind an der lichtmauer zerschellt";

    speed+=inc;
    }

    da gibts viele moeglichkeiten, sicher auch bessere als ich hier gezeigt habe - aber worauf ich hinaus will: ich hab noch nie klasse geschrieben die public member hatte, oder wo alle member einen setter und einen getter hatten...

    ich sehe als beim besten willen keinen grund warum es bei dir anders sein sollte. oder willst du diese nachteile wirklich in kauf nehmen??



  • ganz egal, ob man allein arbeiteitet oder im team. protected tut weh.
    wenn man volkards fehlersuchregeln durchstöbert, steht da auch:
    "du bist nicht weniger tapsig, als deine arbeitskollegen. wirksame schutzmechanismen gegen die fremden eumel haste auch gegen dich selbst anzuwenden."

    [ Dieser Beitrag wurde am 27.06.2003 um 07:25 Uhr von volkard editiert. ]



  • du bist nicht weniger tapsig, als deine arbeitskollegen. wirksame schutzmechanismen gegen die fremden eumel haste auch gegen dich selbst anzuwenden.

    Amen!!!!

    Stefan.


Anmelden zum Antworten