Initialisierungsliste oder Initialisierung im Konstruktor



  • wenn ich eine Klasse anlege und die privaten Membervariablen initialisieren möchte ist es besser dies mit einer Initialisierungsliste zu machen oder besser im Konstruktor?
    Hab mal beides gemacht und gesehen, dass die Initialisierung im Konstruktor eine höhere Priorität hat. Was ist besser?
    also zb:

    class myclass{
    private:
        double m_messwert;
    public:
        myclass() : m_messwert(0){
            m_messwert = 1;
        }
    };
    


  • rudpower schrieb:

    wenn ich eine Klasse anlege und die privaten Membervariablen initialisieren möchte ist es besser dies mit einer Initialisierungsliste zu machen oder besser im Konstruktor?

    Initialisieren ist ausschließlich in der Initialisierungsliste möglich. Beim betreten des Konstruktorrumpfes ist die Initialisierung bereits erfolgt (im Zweifel über den Standardkonstruktor der Variablen, es sei man verwendet eine Initialisierungsliste ). Statt einer Initialisierung wird hier eine Zuweisung durchgeführt.

    In bestimmten Fällen muss man ohnehin die Initialisierungsliste verwenden. Letztere ist daher auch der optimale Weg.

    Siehe hierzu auch den FAQ-Eintrag.


  • Mod

    rudpower schrieb:

    wenn ich eine Klasse anlege und die privaten Membervariablen initialisieren möchte ist es besser dies mit einer Initialisierungsliste zu machen oder besser im Konstruktor?
    Hab mal beides gemacht und gesehen, dass die Initialisierung im Konstruktor eine höhere Priorität hat. Was ist besser?

    Normalerweise die Initialisierungsliste. Aus der Bemerkung mit der "Priorität" entnehme ich aber, dass du den Vorgang beim Konstruieren eines Objektes nicht ganz verstanden hast. Hier eine Erklärung:

    Betrachte eine einfache Klasse ohne Vererbung. Was passiert beim Konstruktoraufruf? Zuerst wird der Konstruktor von allen Membervariablen aufgerufen. Taucht die Membervariable in der Initialisierungsliste auf, so wird der Konstruktor so wie in der Initialisierungsliste angegeben aufgerufen. Fehlt die Membervariable in der Initialisierungsliste, so wird der Default-Konstruktor aufgerufen. Danach wird der Code im Konstruktor ausgeführt.

    Wie du siehst sparst du dir bei Verwendung der Initialisierungsliste ein paar unnötige Schritte. Denn anstatt erst den Defaulkonstruktor aufzurufen und dann eine Zuweisung zu machen, rufst du nur den Konstruktor mit den richtigen Argumenten auf.

    Das was du als "Priorität" bezeichnest ist einfach nur die Ausführungsreihenfolge. Zuerst hast du die Membervariable wie in der Initilaisierungsliste angegeben konstruiert und ihr danach im eigentlichen Konstruktor doch einen anderen Wert zugewiesen.

    Initialisierungslisten haben auch den Vorteil, dass man Membervariablen ohne Defaultkonstruktor haben kann.



  • ah alles klar. Eine Initialisierung ist ja auch eine Erstzuweisung. Wenn also in meinem Beispiel der Membervariablen m_Messwert der Wert 1 zugewiesen wird, wird der Wert 0 von der Initialisierung in der Konstruktorliste überschrieben. Und gibt es diese Liste nicht wird die Membervar. ja schon vor der Zuweisung im Konstruktorrumpf mit einem zufälligen Wert initialisiert.



  • rudpower schrieb:

    Und gibt es diese Liste nicht wird die Membervar. ja schon vor der Zuweisung im Konstruktorrumpf mit einem zufälligen Wert initialisiert.

    Nur bei PODs und nicht mit einem wirklich zufälligen Wert, sondern mit dem, was da eben grad zufällig im Speicher steht.

    Das hättest du alles allerdings auch durch einen Blick in die FAQ gleich nachlesen können, ohne erst auf die Antworten hier warten zu müssen...



  • möchte ich jetzt in der Klasse ein Objekt einer anderen Klasse erzeugen deklarier ich dieses auch als private und definier es als Public also zB AnsiString Objekt:

    class myclass{
    private:
        AnsiString* mystring;
    public:
        myclass() : ??? { };
    };
    

    wie ist es da? Normal würd ich ja mit

    mystring = new AnsiString;
    

    definieren. Vor allem was ist wenn ich auf das Objekt (mystring) nun über andere Dateien zugreifen will. Ein Kollege riet mir das einfach global zu definieren und in der Header-Datei als extern zu deklarieren. Nur frag ich mich ob das guter Stil ist?



  • rudpower schrieb:

    wie ist es da? Normal würd ich ja mit

    mystring = new AnsiString;
    

    definieren.

    mycalss() : mystring(new AnsiString()), othermember(othermembersinitialvalue) {}
    

    Immer nach dem selben Schema. IN klammern hinter dem Membernamen die Initialisierungsparameter.

    Vor allem was ist wenn ich auf das Objekt (mystring) nun über andere Dateien zugreifen will. Ein Kollege riet mir das einfach global zu definieren und in der Header-Datei als extern zu deklarieren. Nur frag ich mich ob das guter Stil ist?

    Das hat ja mit der Initialisierungsliste erstmal garnichts zu tun. Das global zu machen ist Humbug und was völlig anderes, eine globale Variable gibts nur einmal, eine Membervariable gibts einmal für jedes Objekt. DU könntest mal nach Gettern und Settern googlen. Allerdings legen die Fragen nach so grundsätzlichen Dingen nahe, dass du eventuell nochmal ein ordentliches Buch durcharbeiten solltest (und dein Kollege vielleicht auch).



  • get und set kenn ich schon. damit bekomm ich halt Zugriff auf die privaten Instanzvariablen also zB

    class A{
    private:    
        int x;
        bool wahr;
    public:
        void setwerte(int x, bool wahr) {this->x = x; this->wahr=wahr;}
        int getx(void) {return x;}
    };
    

    Die Frage mit dem Zugriff von anderen cpps war, weil ja Form-Dateien in C++Builder und VisualStudio auch immer Klassendateien sind und ich dort so ein Fall habe. Dort habe ich dann von mir verwendete Variablen und Methoden in die Klasse der Form geschrieben, da diese zu der Form gehören. Und in den verschiedenen Forms brauche ich Methoden und Variablen anderer Klassen. Die Objekte wollt ich halt dann auch in der Form deklarieren und definieren. Deshalb brauchte ich die Info ob man das auch mit der Initialisierungsliste machen kann.



  • rudpower schrieb:

    Ein Kollege riet mir das einfach global zu definieren und in der Header-Datei als extern zu deklarieren. Nur frag ich mich ob das guter Stil ist?

    Nein, genauso wenig wie die anderen Dinge die ich bei dir ansatzweise sehe:

    1. Warum AnsiString als Zeiger, und nicht als Wert deklarieren? In der VCL gibt es zwar einige Fälle, in denen man Objekte auf den Heap anlegen muss, AnsiString ist aber kein solcher.

    2. Globales definiteren einer Variablen ist meist Unsinnig. Nur weil der C++ Builder diese Unsitte für alle Datenmodule und Forms umsetzt, solltest du es nicht so machen. Ganz davon abgesehen, das ich dies ohnehin nur in Datenmodulen/Formularen stehen lasse die vom C++ Builder automatisch angelegt werden sollen (Zumal es dann auch nur eine Instanz geben kann).

    Und wenn wirklich nur eine Instanz nötig ist, würde ich eher noch zu statischen Variablen als Globalen greifen.

    rudpower schrieb:

    Dort habe ich dann von mir verwendete Variablen und Methoden in die Klasse der Form geschrieben, da diese zu der Form gehören.

    Bitte nicht so verallgemeinern. Sofern diese WIRKLICH zur Form gehören, okay. Aber pass auf, ob nicht ein MVC-Pattern oder ähnliches manchmal besser wäre (Stärkere Trennung der Daten von der Anzeige...).



  • ja da geb ich Dir recht. Das mit dem AnsiString war nur als Beispiel gedacht für irgendeine Klasse. Natürlich würd ich hier auch einen AnsiString nicht als Zeiger deklarieren. Ich wollte mit meinem Beispiel nur nicht zu konkret werden. Global definier ich auch keine Variablen, das hab ich auch so gelernt. Ich versuch mal kurz zu erklären.
    Habe ein größeres Programmierprojekt und beschäftige mich erst seit November intensiv mit C++. Als Entwicklungsumgebung verwende ich den Builder 5. Ich lese mehrere Messgeräte aus und habe dazu entsprechende Klassen. Diese Messdaten zusammen stehen in einer weiteren Klasse und über einen Timer wird ein Vektor gefüllt. Nun gibt es verschiedene Forms zum Speichern, Einstellen, Ansteuern der Messgeräte usw. Zusätzlich läuft alles über Threads. In der Threadklasse sorgt eine Art Timer (mit QPC) dafür, dass die Messwerte aktualisiert werden und liest ständig den aktuellen Messwert von den verschiedenen Geräten aus. Nun hatt ich immer wieder das Problem, dass ich aus unterschiedlichen Forms, also indem Fall Klassen, an Eigenschaften und Methoden anderer Klassen herankommen muss. Also hab ich versucht zB in Klasse A (also einer Form) ein Objekt der Klasse B als Private in A zu deklarieren. Nun muss ich es (wie ich aus den Antworten dieses Beitrags erfahren habe) im Konstruktor initialisieren und eine GetMethode dafür schreiben, damit ich dann zB in der Threadklasse über das Objekt in A an die Methoden von B rankomme. VOn anderen Klassen muss ich darauf auch zugreifen.
    Alles etwas komplex 🙂 Aber ich seh gerade bei solchen komplexen Sachen immer wieder die Vorteile der OOP. Ich hatte meinem Kollegen, der schon ein paar Jahre Erfahrung darin hat das ganze gezeigt und er meinte, dass es so viel zu komoliziert sei. Ich soll es einfach in der Form deklarieren (also global, da es ja so in keiner Methode steht bzw ausserhalb der Formklasse), über zB den Konstruktor der Form mit "new Klassenname" das Objekt erzeugen, im Header der Form als extern deklarieren und fertig. Naja, funktionieren tut es so aber mir passts so auch nicht. Ich hoff das war jetzt nicht zu viel Geschwafel. Ich werd das morgen gleich mal ausprobieren. Schon mal danke für die Ratschläge und Hilfe.



  • hab das mal ausprobiert und es funktioniert auch so. Nur hab ich immer noch Probleme auf Objekte anderer Klassen zuzugreifen (Siehe Beitrag Zugriff auf Objekte einer Klasse von aussen).



  • rudpower schrieb:

    hab das mal ausprobiert und es funktioniert auch so. Nur hab ich immer noch Probleme auf Objekte anderer Klassen zuzugreifen (Siehe Beitrag Zugriff auf Objekte einer Klasse von aussen).

    Dafür gibts wie schon gesagt getter und setter. Die direkt zugreifbar zu machen würde die Kapselung aufbrechen und ist im Normalfall nicht sinnvoll.



  • wie es bei normalen Variablen mit Get und Set funktioniert weiss ich, nur wie ist es bei Objekten an die ich rankommen will. Ich brauch die Methode eines Objekts einer anderen Klasse.



  • Was unterscheidet denn eine "normale Variable" von einem "Objekt"? Oder was genau verstehst du unter diesen Begriffen? Etwas Code zur Veranschaulichung wäre sicher auch von Nutzen.



  • hab eine Get-Methode geschrieben und nun funktioniert es. Vielen Dank erst mal.
    Hab jetzt das Problem, das der Konstruktor erst bei einer bestimmten Aktion aufgerufen wird (weil er einen Parameter erwartet und diesen der Benutzer zur Laufzeit eingeben muss). Nun habe ich eine private Deklaration einer Variablen und hab dazu eine Getmethode. Problem ist, das ich diese Variable (ist eine bool Variable) in dem Konstruktor per Konstruktorliste initialisiert habe und sie im Konstruktor auf true gesetzt habe. Nun muss ich aber in einer anderen Klasse abfragen ob die Variable true oder false ist.
    Da der Konstruktor erst bei einer Aktion (hier ist es ein Buttonklick) aufgerufen wird habe ich vorher den falschen Wert der Variable. Wie kann ich das Problem beheben?


  • Mod

    Du hast da irgendetwas katastrophal falsch designed. Man muss NIE auf ein Objekt zugreifen, bevor der Konstruktor aufgerufen wurde. Denn bevor dies geschieht, existiert das Objekt ja überhaupt nicht!


Anmelden zum Antworten