tiefer in den C'tor



  • class B
    {
       public:
        B() : Bi(100){}
        private:
           int Bi;
    };
    class D : public B
    {
        public :
           D():B(), Di(100){} 
        private:
           int Di;
    };
    
    D d;
    

    man sagt mir, C'tor ist nicht anders als "alloc und init".Die Reihenfolge sei:

    1. [b]bevor [/b]D() aufgerufen wird, sind plätze für D und B allokiert, hier plätze für Bi und Di, welche noch nicht initializiert sind, und Zeiger auf D festgelegt.
    2.ruf B() auf, init Bi
    3. ruf D() auf, init Di
    

    alloc wird daher nur eimal aufgerufen, ist die Aussage richtig? was passiert hier wenn ich

    B(), Di(100)
    

    platz umtauschen, wird dann Di zuerst initialisiert?
    zeigt der Zeiger wirklich nur auf D?
    wenn bevor init von B aufgerufen wird, ist der platz schon da, dann wieso kann ich nicht

    D():B(), Bi(100){}
    

    schreiben?



  • Das ändern der Reihenfolge ändert nichts an der Initialisierung. Soweit ich weiß werden Member auch in der Reihenfolge ihrer Deklaration initialisiert. Der Konstruktor allokiert nichts. Er wird erst aufgerufen, wenn Speicher für das Objekt da ist. Wahr ist, dass ein Objekt vom Typ D nun im Grunde so groß ist wie Bi und Di zusammen (der Compiler kann da noch was drehen, aber das interessiert meistens nicht so...) Ein Zeiger kommt im ganzen Beispiel nicht vor.



  • Der Konstruktor allokiert nichts. Er wird erst aufgerufen, wenn Speicher für das Objekt da ist.

    1.was heisst das? ich glaub schon, eine allokation passiert hier, falls kein genug Speicher vorhanden ist, schlägt bei Erzeugung des Obj fehl,
    2.jedes Obj hat einen this pointer



  • netrobot schrieb:

    Der Konstruktor allokiert nichts. Er wird erst aufgerufen, wenn Speicher für das Objekt da ist.

    1.was heisst das? ich glaub schon, eine allokation passiert hier, falls kein genug Speicher vorhanden ist, schlägt bei Erzeugung des Obj fehl,
    2.jedes Obj hat einen this pointer

    Ja, die Erzeugung. Die passiert vor dem Konstruktoraufruf. Der Konstruktor dient dazu, das Objekt mit gültigen Daten zu "befüllen". Ansonsten wäre in den Variablen (wie man es von C gewohnt ist) einfach nur Datenmüll. Der this-Pointer wird nur den Methoden übergeben. Im Grunde ist eine Methode nämlich eine Funktion. Und woher soll die arme Funktion wissen, was vor dem .-Operator steht? Richtig, der this-Zeiger sagt es der Funktion. Das Objekt schleppt den nicht mit sich rum, nein, this zeigt auf dein Objekt!



  • Der Speicher wird, wie bereits gesagt, zuerst allokiert, dann wird der Konstruktor aufgerufen.
    Die Basisklasse wird immer zuerst initialisiert und damit kommen wir auch bereits zu deiner nächsten Frage die Reihenfolge in der Initialisierungsliste hat nichts mit der tatsächlichen Reihenfolge der Initialisierung zu tun. Die wird durch die Reihenfolge der Attribute (=Klassenvariablen) in der Klassendefinition festgelegt.



  • Der Speicher wird, wie bereits gesagt, zuerst allokiert, dann wird der Konstruktor aufgerufen

    allokiert für B und D? und dann werden die Konstructor hintereinander aufgerufen, zuerst B Ctor dan D Ctor



  • ...allokiert für einen Block, der ausreichend groß ist, um ein Objekt der Klasse D aufzunehmen. Dazu gehört auch der Platz den die Oberklassen (B) und deren Member brauchen, plus das ein- oder andere Implementationsdetail (z.B. vtable).
    Und dann werden die Konstruktoren von "oben nach unten" (also von der obersten Oberklasse bis runter zur entferntesten Ableitung) ausgeführt.



  • allokiert für einen Block, der ausreichend groß ist, um ein Objekt der Klasse D aufzunehmen

    was heisst ausreichend, ich schätze die Grössen sind von Compiler zu Compiler unterschiedlich



  • netrobot schrieb:

    allokiert für einen Block, der ausreichend groß ist, um ein Objekt der Klasse D aufzunehmen

    was heisst ausreichend, ich schätze die Grössen sind von Compiler zu Compiler unterschiedlich

    Wenn sizeof(D) z.B. 8 ist, dann heisst "ausreichend" eben 8. Und ja, die Grösse kann von Compiler zu Compiler unterschiedlich sein, allerdings sieht man natürlich auch sehr oft die selben Werte.



  • class B
    {
       public:
           int Bi;
    };
    class D : public B
    {
        public :
           D():Bi(100){} //errorC2614: 'D' : illegal member initialization: 'Bi' is          
                        //not a base or member
        private:
           int Di;
    };
    
    D d;
    

    hier wenn Platz schon bevor Ctor allokiert ist, wieso kann ich Bi nicht initialisieren? theoretisch muss es gehen.



  • In der Initialisierungsliste darfst du nur Member der Klasse selbst (also nich der Basisklasse) initialisieren und Basisklassenkonstruktoren aufrufen. Du solltest dich mit diesem Allokieren usw. nicht verrückt machen. Das wird alles für dich vom Compiler erledigt.



  • ja, sowas mache ich auch nicht, ich rede jetzt nur von Theorie, zwar vom memory aus.



  • OK, vom Memory aus: Zuerst besorgt sich das Programm genügend Speicherplatz (bei Stack-Objekten wird das schon beim Compilieren vorbereitet, bei Heap-Objekten erledigt das operator new ), danach wird das Objekt von innen nach außen initialisiert (zuerst die virtuellen Basisklassen, dann die normalen Basisklassen und zuletzt die Membervariablen) und danach landest du im Ctor-Rumpf für deine eigenen Initialisierungen.

    (und mit der Initialisierungsliste legst du fest, welcher Ctor für deine eigenen Sub-Objekte verwendet werden soll - B::Bi wird bereits vom B-Ctor initialisiert, also mußt du dich nicht darum kümmern)



  • die Frage hatte ich schon mal gestellt, leider habe total vergessen.Vielen Dank



  • und mit der Initialisierungsliste legst du fest, welcher Ctor für deine eigenen Sub-Objekte verwendet werden soll - B::Bi wird bereits vom B-Ctor initialisiert, also mußt du dich nicht darum kümmern

    nein, B::Bi ist nicht Initialiert. Der Platz ist nur allokiert, wo irgendwelcher Müll liegt.

    class B
    {
    public:  
      B(){} //hier Bi ist nicht initialisiert.
      int Bi; 
    };
    class D:public B
    {
      D():B(),Bi(100){} //versuche 1.mal Bi zu initialieren, error
    };
    


  • so kannste B::Bi initialisieren.

    class B
    {
    public:  
      B(int b):Bi(b){} // class B: sizeof(int)
      int Bi;
    };
    class D:public B
    {
      D():B(100){} //
    };
    

    Da wie schon gesagt wurde:
    1. es wird ein block allociert
    2. erfolgt meistens 'nen memcpy() der alle Member-Variablen aufeinmal setzt auch die der Base-class.
    will heißen: nen ctor wird ungefär so vom compiler umgesetzt: memcpy(this, <memblock mit den werten>, sizeof(*this));

    class B
    {
       public:
           int Bi;
    };
    class D : public B
    {
        public :
           D():Bi(100){} // würde heißen:  allociere Speicher für D incl. B; rufe
                         // B(), D() auf und erst dann Bi(), da aber B schon
                         // initialisert wurde(als Block) kannste jetzt nur noch
                         // via assigment Bi setzen. 
    
        private:
           int Di;
    };
    

    Theoretisch könnte der Compiler >D():B(),Bi(100)< auf obigen Code umstellen, aber wie willst du sichergehen das Jemand nicht die Structur deiner Base-class durcheinanderbringt, nur weil er inner sub-class nen field der base-class ändern will. -> Kapselung

    nein, B::Bi ist nicht Initialiert. Der Platz ist nur allokiert, wo irgendwelcher Müll liegt.

    Nach dem Ctor einer Klasse werden allen Objecten Werte zugewiesen(Initialiert), egal ob nun von dir explizit vorgegebene oder zufällige.



  • netrobot schrieb:

    und mit der Initialisierungsliste legst du fest, welcher Ctor für deine eigenen Sub-Objekte verwendet werden soll - B::Bi wird bereits vom B-Ctor initialisiert, also mußt du dich nicht darum kümmern

    nein, B::Bi ist nicht Initialiert. Der Platz ist nur allokiert, wo irgendwelcher Müll liegt.

    OK, formuliere ich den Satz halt um - B::Bi sollte vom B-Ctor initialisiert werden.


Log in to reply