protected Vererbung



  • Diese Klasse hat die unglaubliche Größe von 32 Byte.
    Wie gibts das. char sagen wir mal 4 Byte *2 + 2*double = 24 Byte

    Wahrscheinlich um auf eine gerade Speicheradresse zu kommen.

    Das Padding kann ja ganz schön speicher kosten 🙂

    class B
    {
    public:
    	B(void);
    	~B(void);
    private:
    	char m_1;
    	double m_3;
    	char m_2;
    	double m_4;
    };
    


  • Zeus schrieb:

    Double hat die Große 8
    Int hat die Größe 4
    Pointer ist ebenfalls 4.

    Diese Größen sind (strenggenommen) Compiler- und System-abhängig.
    Bei meinem 64-bit System ist ein Pointer z. B. 8 Byte.
    -> Ich vermute du hast (noch) ein 32-bit System?



  • blurry333 schrieb:

    Diese Klasse hat die unglaubliche Größe von 32 Byte.
    Wie gibts das. char sagen wir mal 4 Byte *2 + 2*double = 24 Byte

    Wahrscheinlich um auf eine gerade Speicheradresse zu kommen.

    Das Padding kann ja ganz schön speicher kosten 🙂

    class B
    {
    public:
    	B(void);
    	~B(void);
    private:
    	char m_1;
    	double m_3;
    	char m_2;
    	double m_4;
    };
    

    Änder einfach mal die Reihenfolge in char, char, double, double oder
    in double, double, char, char und du hast (wahrscheinlich) nur noch 24 Byte



  • Nö, 64 bit, heisst aber nicht, dass ich auch in 64-Bit Mode kompiliere *gg*



  • Zeus schrieb:

    Nö, 64 bit, heisst aber nicht, dass ich auch in 64-Bit Mode kompiliere *gg*

    Mir war klar, dass du nur die Größenangaben begründen wolltest.
    Die 32-bit Aussage ging Richtung blurry333

    Hast du wirklich im 32bit Modus kompiliert? Ich hätte gesagt, du hast gar nichts kompiliert 😉



  • CSpille schrieb:

    Zeus schrieb:

    Double hat die Große 8
    Int hat die Größe 4
    Pointer ist ebenfalls 4.

    Diese Größen sind (strenggenommen) Compiler- und System-abhängig.
    Bei meinem 64-bit System ist ein Pointer z. B. 8 Byte.
    -> Ich vermute du hast (noch) ein 32-bit System?

    Ups ich hab ja auch ein 64 Bit Windows 7 Betriebssystem.



  • aber :

    int main()
    {
    int y=7;
    int *x=&y;	
    
    cout<<sizeof(x);  // Ausgabe 4 Byte !!!
    }
    

  • Mod

    Dann hast du dein Programm wohl für 32 Bit kompiliert.



  • blurry333 schrieb:

    WAnn macht es Sinn den Destruktor selbst zu definieren. ABgesehen von virtual destruktor ?

    Einen eigenen Destruktor brauchst Du immer dann, wenn der Defaultdestruktor nicht alles abräumen kann. Der Defaultdestruktor ruft einfach die Destruktoren aller Membervariablen auf. Sonst macht der nichts. Wenn eine Deiner Membervariablen z.B. ein Pointer ist, mußt Du einen eigenen Destruktor erzeugen, der den Speicher eventuell frei gibt:

    class x
    {
        TYPE *pointer;
        x() { pointer=NULL }
        ~x() { if( pointer ) free(pointer); }    // oder delete pointer;
    
        ....
    };
    

    Der Default destruktor würde den Speicher nicht freigeben. Gleiches gilt auch für Filehandles, Fensterhandles und ähnliches.

    mfg Martin



  • mgaeckler schrieb:

    ~x() { if( pointer ) free(pointer); }    // oder delete pointer;
    

    mgaeckler meinte natürlich:

    ~x() { if( pointer ) delete pointer; }    // oder (in Ausnahmen) free(pointer);
    

    Jetzt verführ keinen Neuling dazu malloc und free zu benutzen 😮

    @blurry333: In C++ verwendet man i. d. R. new und delete 😉



  • blurry333 schrieb:

    oki 🙂

    Was ich immer noch nicht versteh welchen Sinn macht es,
    einen Basisklassen Zeiger auf eine abgeleitete Klasse zeigen zu lassen.

    Ich habe beispielsweise eine Klassenbibliothek für die Windows API.

    Die Basisklasse kapselt das Fensterhandle. Abgeleitete Klassen spezialisieren sich dann immer mehr:

    Selbstdefinierte Windowsklassen,
    Edit Controls, Comboboxen, Listboxen, MDI-Fenster, MDI-Childs usw. usf.

    Einer meiner Container enthält eine Liste aller Fenster mit selbst definierten Klassen. Der Container selber kennt aber nur die BASIS-Klasse aller selbst defnierten Fenster. Applikationsspezifische Klassen kann er gar nicht kennen, da er Teil der Bibliothek ist.

    Er liefert daher immer nur einen Zeiger auf die Basisklasse zurück. Wenn der Anwendung in dem Kontext das auch genügt, wird sie das auch so lassen. Ansonsten muß halt gecastet werden.

    Der Container ist auch dafür verantworlich, Windows Messages an die Instanzen der Fensterklassen zu verteilen. Dafür sind dann die virtuellen Funktionen zwingend erforderlich, da er applikationsspezifische Messagehandler gar nicht kennen kann.

    Generel brauchst Du das, wenn ein Container Zeiger auf Instanzen von Klassen speichern muß, bei denen er nur die Basisklasse kennt.

    mfg Martin



  • CSpille schrieb:

    Jetzt verführ keinen Neuling dazu malloc und free zu benutzen 😮

    Was soll an

    char *x=new char[100];
    ...
    delete [] x;
    

    besser sein als an

    char *x =(char *)malloc( 100 );
    ...
    free( x );
    

    ?

    OK, ich muß den Zeiger nicht casten, aber das ist ja wohl ein akademischer Unterschied.

    Hab ich was übersehen?

    mfg Martin



  • mgaeckler schrieb:

    CSpille schrieb:

    Jetzt verführ keinen Neuling dazu malloc und free zu benutzen 😮

    Was soll an

    char *x=new char[100];
    ...
    delete [] x;
    

    besser sein als an

    char *x =(char *)malloc( 100 );
    ...
    free( x );
    

    ?

    OK, ich muß den Zeiger nicht casten, aber das ist ja wohl ein akademischer Unterschied.

    Hab ich was übersehen?

    mfg Martin

    Weiss nicht ob Du's übersehen hast, aber...
    Bei new und delete wird der Konstruktor und Destruktor aufgerufen. Bei malloc und free nicht. Spielt bei char keine Rolle... aber eben nicht geeignet, das dem Anfänger hinzuschmeissen.

    Simon



  • Nicht gut:

    mgaeckler schrieb:

    class x
    {
        TYPE *pointer;
        x() { pointer=NULL }
        ~x() { if( pointer ) free(pointer); }    // oder delete pointer;
    
        ....
    };
    

    Besser:

    class x 
    {
    public:
       x() : pointer(new x())   // Initalisierungsliste 
       {
       }
    
       ....
    
    private:
       x* pointer;
    }
    


  • mgaeckler schrieb:

    OK, ich muß den Zeiger nicht casten, aber das ist ja wohl ein akademischer Unterschied.

    Als C++-Programmierer bevorzugst du ja wohl (i. d. R.) ein std::vector<char> ,oder? 😉



  • theta schrieb:

    Weiss nicht ob Du's übersehen hast, aber...
    Bei new und delete wird der Konstruktor und Destruktor aufgerufen. Bei malloc und free nicht. Spielt bei char keine Rolle... aber eben nicht geeignet, das dem Anfänger hinzuschmeissen.

    Simon

    Richtig bei Klasseninstanzen sind natürlich malloc und free *VERBOTEN*.

    Aber bei allen anderen benutze ich (vieleicht auch einfach aus Gewohnheit) nach wie vor malloc und free.

    mfg Martin



  • Zeus schrieb:

    Besser:

    class x 
    {
    public:
       x() : pointer(new x())   // Initalisierungsliste 
       {
       }
    
       ....
       
    private:
       x* pointer;
    }
    

    ui... Nice endless loop... Aber egal... 🙄

    Was für einen Vorteil hat denn die Initialisierungsliste, wenn ich einen
    Zeiger zuweise?

    Klar, bei Referenzen ist es notwendig.

    Ist das nur stilistisch oder auch ein anderer Vorteil?



  • mgaeckler schrieb:

    Richtig bei Klasseninstanzen sind natürlich malloc und free *VERBOTEN*.

    Aber bei allen anderen benutze ich (vieleicht auch einfach aus Gewohnheit) nach wie vor malloc und free.

    OK es gibt natürlich noch einen Grund für new und delete (bei Anfängern):

    TYPE *ptr = (TYPE*)malloc( 100 * sizeof( TYPE ) );

    vs.

    TYPE *ptr = new TYPE[100];

    Mal schauen, ob ich in meinen Beispielen in Zukunft new statt malloc nehmen kann. 🙄

    mfg Martin



  • Was steht sonst in den Zeiger drin?

    Ganz einfach schrott.

    Für das delete breitet glaub keine Probleme wenn du eine nicht gültige Adresse deletes, aber deine Programmlogik geht wohl flöten. Außerdem bei komplexeren Klassen wenn du mehrere Member und Basisklassen hast, wird zu komplex den Pointer nicht zu initialisieren, dann aber eher mit 0 oder ne Übergabe^^.



  • Zeus schrieb:

    Nicht gut:

    mgaeckler schrieb:

    class x
    {
        TYPE *pointer;
        x() { pointer=NULL }
        ~x() { if( pointer ) free(pointer); }    // oder delete pointer;
    
        ....
    };
    

    Besser:

    class x 
    {
    public:
       x() : pointer(new x())   // Initalisierungsliste 
       {
       }
    
       ....
       
    private:
       x* pointer;
    }
    

    Das würd ich nicht machen. Wenn der Konstruktor von x einen neues Objekt von x erzeugt, wird der Konstruktor von x nochmal aufgerufen, der wieder ... naja irgendwann einmal gibt es einen Stack overflow oder Deine Maschine trasht.


Anmelden zum Antworten