Verständnisfrage Kapselung und Variablen-Zugriff



  • Hallo Nexus,

    danke für Deine Hilfe.

    Nexus schrieb:

    Dein Code ist nicht gerade ein übliches Beispiel für Kapselung. Die Klasse benötigt die Variablen nicht als dauerhafte Eigenschaft, sondern nur im Verlaufe einer Operation. Das legt nahe, statt einer Klasse eine freie Funktion zu wählen, möglicherweise in einem Namespace.

    Ja, Variablen-Zugriff ist vielleicht besser gewählt, war mir sebst nicht sicher wie ich das beschreiben soll. Ich habe in der Klasse mehrere Funktionen und einige Funktionen brauchen die Variablen zur Verarbeitung, aber nicht permanent. Bei meinem Beispiel waren das jetzt nur 2 Variablen, was macht man aber wenn es mehrere sind ? Alle in ein struct packen und dann per Referenz oder doch als private ?

    Nexus schrieb:

    Falls die Variablen aber während der ganzen Lebensdauer der Klasse von Bedeutung sind, musst du dir überlegen, ob du sie bereits am Anfang im Konstruktor setzen willst und nachher nicht mehr veränderst.

    Als Konstanten geht das nicht, ich muss sie verändern können.

    Nexus schrieb:

    Andernfalls würde ich wie gesagt keine Memberfunktion dafür machen, da die Funktion gerade so gut frei sein könnte und nicht für die Klasseninterna als Schnittstelle dient.

    Mh, das hiese dann das Klassenkonzept verwerfen ?

    Trial schrieb:

    z.B. wenn die Funktion oft aufgerufen wird ist die Methode 1 mit den Argumenten sicherlich langsamer.

    Woher bist du dir da so sicher? 😉

    Nur eine Annahme 😉



  • Trial schrieb:

    Mh, das hiese dann das Klassenkonzept verwerfen ?

    Ja!

    Kein Mensch mag

    CTest ct;
    ct.add(3,4);
    cout<<ct.getResult();
    

    schreiben, wenn er

    cout<<3+4;
    

    meint.

    halte dich am besten zunächst an die regel, daß nur dinge, die man anfassen kann, zu klassen werden. sachen, die man nicht anfassen kann, wie sortieralgorithmen, flächenberechnungen und so, taugen wenig.



  • Trial schrieb:

    Ja, Variablen-Zugriff ist vielleicht besser gewählt, war mir sebst nicht sicher wie ich das beschreiben soll. Ich habe in der Klasse mehrere Funktionen und einige Funktionen brauchen die Variablen zur Verarbeitung, aber nicht permanent. Bei meinem Beispiel waren das jetzt nur 2 Variablen, was macht man aber wenn es mehrere sind ? Alle in ein struct packen und dann per Referenz oder doch als private ?

    Referenz und struct würde ich eher nicht machen. Allerdings weiss ich immer noch nicht genau, wie du es meinst.

    Wenn es sich um eine Berechnungsklasse handelt und die Funktionen intern Berechnungen ausführen, ist das schon okay. Wenn allerdings die Operanden über längere Zeit gebraucht werden, würde ich sie in der Klasse als Member speichern. Setzen könnte man sie dann über den Konstruktor oder Setter.

    Trial schrieb:

    Mh, das hiese dann das Klassenkonzept verwerfen ?

    Für diesen Fall schon. Ich bezog mich auf eine Memberfunktion, die gerade so gut als freie Funktion stehen könnte, weil sie nichts mit der Klasse zu tun hat.

    int CTest::Add(int Left, int Right);
    

    macht für mich keinen Sinn, wenn wirklich nur addiert wird. Wird intern noch etwas mit dem Ergebnis oder den Argumenten gemacht, ist das wieder etwas anderes.



  • Das mit den 2 Summanden addieren war nur ein Beispiel. In den Funktionen wird schon noch mehr gemacht, aber es gibt verschiedene Variablen die von mehreren Funktionen genutzt werden. Das alles beschreibt einen Parser für Element Daten und ich habe das ganze Geraffel mit Funktionen jetzt zu einer Klasse zusammengefügt, um auch eine bessere Übersicht zu bekommen.

    Spricht da was gegen ein Klassenkonzept ? Auch wenn man nicht mehrere Objekte erzeugen muss ?



  • Trial schrieb:

    Spricht da was gegen ein Klassenkonzept ? Auch wenn man nicht mehrere Objekte erzeugen muss ?

    Musst du denn überhaupt Objekte erzeugen?

    Wenn du nur die Funktionen brauchst, schreibst du eben eine Funktionssammlung. Diese kannst du in einen Namensraum einbetten, um die Zusammengehörigkeit zu verstärken.



  • Trial schrieb:

    Das mit den 2 Summanden addieren war nur ein Beispiel. In den Funktionen wird schon noch mehr gemacht, aber es gibt verschiedene Variablen die von mehreren Funktionen genutzt werden.

    nur um übergaben zu sparen, die zum member zu machen, ist keine feine sache.

    Das alles beschreibt einen Parser für Element Daten und ich habe das ganze Geraffel mit Funktionen jetzt zu einer Klasse zusammengefügt, um auch eine bessere Übersicht zu bekommen.

    ich hab immer nur rekursive abstiegsparser gebaut. die parserei bestand nur aus funktionen. die klassen waren die erzeugten datenobjekte. es gab keine klasse namens Parser oder so.

    Spricht da was gegen ein Klassenkonzept ? Auch wenn man nicht mehrere Objekte erzeugen muss ?

    dazu kenne ich deinen parser nicht gut genug. wenn du keine attribute baust, nur um übergaben zu sparen, und wenn dann die klassen attributlos werden, dann war die klasse nur ne funktionensammlung und es riecht nach namespace.
    oder klasse mit lauter static funktionen, das ist im prinzip auch nix anderes, nur nicht so praktisch.



  • Nexus schrieb:

    Musst du denn überhaupt Objekte erzeugen?

    Nein, da hast Du recht. Das bedingt nur das Klassenkonzept.

    Nexus schrieb:

    Wenn du nur die Funktionen brauchst, schreibst du eben eine Funktionssammlung. Diese kannst du in einen Namensraum einbetten, um die Zusammengehörigkeit zu verstärken.

    Wie sieht denn so eine Funktionssammlung aus ? Kann mir im Moment nichts drunter vorstellen. Hast Du da noch einen Denkanstoß für mich ?

    Danke ! :xmas1:



  • einfach ein haufen funktionen, die was miteinander zu tun haben.
    wie zum beispiel http://watteimdocht.de/jngl/wiki/Reference



  • Danke Volkard,

    dann werde ich mir den namespace mal zu Gemüte führen 🙂



  • Hab doch noch eine Frage. Hab ich das so richtig verstanden, z.B.

    *.h Datei

    namespace MyNamespace
    {
     int A(int a, int b);
    
     int B(int a, int b);
    }
    

    *.cpp Datei

    int MyNamespace::A(int a, int b)
     {
      return a + b;
     }
    
     int MyNamespace::B(int a, int b)
     {
      return a * b;
     }
    

    Prototypen in die Header-Datei und die Funktionen in die Implementierungs-Datei ?



  • Trial schrieb:

    Prototypen in die Header-Datei und die Funktionen in die Implementierungs-Datei ?

    Ja, das stimmt. Aber wieso machst du nicht Folgendes?

    // .cpp-Datei
    namespace MyNamespace
    {
    
    int A(int a, int b)
    {
      return a + b;
    }
    
    int B(int a, int b)
    {
      return a * b;
    }
    
    } // namespace MyNamespace
    


  • [quote="Trial"]Hab doch noch eine Frage. Hab ich das so richtig verstanden, z.B.[/cpp]
    im prinzip ja.
    allerdings wird der parser vermutlich aus recht vielen funktionen bestehen, von denen nur ganz wenige, vielleicht sogar nur eine einzige, in der header-datei verraten werden. glück gehabt. denn das ständige aktualisieren der header-datei, wenn sich in der implementierungsdatei was ändert, nervt gehörig.



  • Das Prinzip der Kapselung ist bei der modularen Programmierung eigentlich das gleiche wie bei der objektorientierten:

    Die Schnittstelle wird öffentlich gemacht ( public in Klassen, Headerdatei bei Dateien), die Implementierung vom Benutzer verborgen ( private , Implementierungsdatei). So erhält man Abstraktion und kann etwas an der Implementierung verändern, ohne die Schnittstelle zu berühren.



  • Das mit den Prototypen in einer Header-Datei hab ich im Prinzip nur deshalb gewählt, weil ich mir denke, wenn ich z.B. 1-2 Jahre an dem Programm nichts mehr gemacht habe, dann habe ich nach dieser Zeit in der Header-Datei einen besseren Überblick von den einzelnen Funktionen. Wenn ich das alles in die *.cpp Datei packe, und da sind Funktionen mit mehreren Seiten Code dabei, dann ist das absolut unübersichtlich.

    Ihr habt mir sehr geholfen !

    Ich wünsch euch einen guten Rutsch nach 2009 🤡


Anmelden zum Antworten