protected Vererbung
-
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 ByteWahrscheinlich 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 blurry333Hast 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 !!! }
-
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.
-
mgaeckler schrieb:
Aber bei allen anderen benutze ich (vieleicht auch einfach aus Gewohnheit) nach wie vor malloc und free.
Warum? wirkt für mich sehr inkonsistent. Vergleiche darüber hinaus auch folgende Anweisungen bezüglich Länge und Lesbarkeit:
int *i = (int*)malloc(sizeof(int)); int *i = new int;Ein Problem ist auch noch, dass dir die Regel bei generischer Programmierung um die Ohren fliegt. Wenn du z.B. ein
typedef int IntTypehast und du das später durch eine Integer-Klasse ersetzen möchtest, fliegt dir das um die Ohren, weil du malloc und free verwendet hast. Bei new und delete wären keine Anpassungen notwendig gewesen. Zusammengefasst gibt es also viele Nachteile und keine Vorteile von malloc und free vs. new und delete.CSpille schrieb:
Ist das nur stilistisch oder auch ein anderer Vorteil?
Wenn man die Initianlisierungsliste nicht nutzt, sondern die Werte im Konstruktor zuweist, wird für die Member vorher der Default-Konstruktor aufgerufen. Mit der Initialisierungsliste ruft man explizit einen evntl. anderen Konstruktor auf. Das spart Performance, weil der Default-Konstruktor entfällt und ist nötig bei Typen, die gar keinen Default-Konstruktor haben (wie eben z.B. Referenzen). Bei Zeigern wird es keine Rolle spielen, weil der Compiler das sicher wegoptimiert, aber auch hier gibt es keinen Grund, bewusst inkonsistent zu sein und Zeiger anders als andere Typen zu behandeln.