Operationen mit mehreren Klassen
-
ja natürlich, mit den Konstruktoren kann ich was anfangen. KX,KY..usw ist klar. Aber was bestimmt jetzt genau, in welcher Reihenfolge die dinger ausgegeben werden. Also ich weiß nicht so recht wann sich das Programm in welcher Klasse befindet. dieses
Y y und
X x [2][1] was ist das ? Dieses Große X und Y steht für die KLasse aber die Kleinbuchstaben ? Wenn das Variablen sind, wo genau erfolg die deklaration ?
-
vatan89 schrieb:
Wenn das Variablen sind, wo genau erfolg die deklaration?
das ist die deklaration, was du meinst ist die definition, welche hier nicht benötigt wird. Die Variablen werden mit dem Standardkonstruktor aufgerufen
vatan89 schrieb:
X x [2][1]
Die eckigen Klammern sind Array-Klammern
-
// Füge Headerdatei ein #include <iostream> // std::cout // Benutze Namensraum std / verwerfe das nötige Voranstellen von std:: using namespace std; // Definiere Klasse X class X{ public: // Ctor & Dtor X () {cout<<"KX"<<endl;} ~ X () {cout<<"DX"<<endl; } }; // Definiere Klasse Y class Y{ private: // Array mit 2x1 Instanz der Klasse X X x [2][1]; public: // Ctor & Dtor Y () {cout<<"KY"<<endl;} ~ Y () { cout<<"DY"<<endl; } }; // Definiere Klasse Z class Z{ private: // Instanz der Klasse Y Y y; // Instanz der Klasse X X x; public: // Ctor & Dtor Z () {cout<<"KZ"<<endl;} ~ Z () { cout<<"DZ"<<endl; } }; // Definiere Programm-Einstiegsfunktion int main (){ // Code-Block (Scope kann ausgenutzt werden, um temporäre Objekte automatisch wieder zerstören zu lassen) { // Erstelle Instanz der Klasse Y Y y; // Erstelle Instanz der Klasse X X x; } // Erstelle dynamisch ein Array mit 2 Instanzen der Klasse Z Z* ZPtr = new Z[2]; // Führe System-Befehl "pause" aus / warte auf Eingabe system ("pause"); // Beende Program mit Rückgabewert 0 (gebräuchliche Status-Angabe für 'alles in Ordnung') return 0; }KX <-- Zeile 45: Erstellung von erstem X in Y = Konstruktor von X
KX <-- Zeile 45: Erstellung von zweitem X in Y = Konstruktor von X
KY <-- Zeile 45: Konstruktor von Y
KX <-- Zeile 47: Konstruktor von X
DX <-- Zeile 48: Verlassen des Scopes = Zerstörung von x = Destruktor von X
DY <-- Zeile 48: Verlassen des Scopes = Zerstörung von y = Destruktor von Y
DX <-- Zeile 48: Verlassen des Scopes = Zerstörung von y = Zerstörung des ersten X in Y = Destruktor von X
DX <-- Zeile 48: Verlassen des Scopes = Zerstörung von y = Zerstörung des zweiten X in Y = Destruktor von X
KX <-- Zeile 50: Erstellung von erstem Z = Erstellung von Y in Z = Erstellen von erstem X in Y in Z = Konstruktor von X
KX <-- Zeile 50: Erstellung von erstem Z = Erstellung von Y in Z = Erstellen von zweitem X in Y in Z = Konstruktor von X
KY <-- Zeile 50: Erstellung von erstem Z = Erstellung von Y in Z = Konstruktor von Y
KX <-- Zeile 50: Erstellung von erstem Z = Erstellung von X in Z = Konstruktor von X
KZ <-- Zeile 50: Erstellung von erstem Z = Konstruktor von Z
KX <-- Zeile 50: Erstellung von zweitem Z...
KX <-- ...
KY <-- ...
KX <-- ...
KZ <-- ... (selbe wie beim ersten)Das Array in Zeile 50 wurde dynamisch erstellt, also zur Laufzeit, und wird daher nicht automatisch zerstört, deswegen findet keine Zerstörung einer Instanz von Z statt.
-
Ich werfe mal das Stichwort "Initialisierungsliste" in den Raum, damit wird das evtl. etwas klarer:
class X { public: X() : m_int(5), m_y() {} private: int m_int; Y m_y; }Die Initialisierungsliste kann weggelassen werden, dann werden alle Member als default initialisiert (sofern dies möglich ist, ansonsten gibts ne Fehlermeldung).
Somit sollte auch klar sein, dass die Member initialisiert werden, *bevor* der Rumpf des Konstruktors aufgerufen wird.
-
KX //Durch das X x [2][1] wird das KX zweimal ausgegeben KX // KY //Anschließend tritt der Konstruktor von Class Y KX //und von der Class X DX // Destruktor von Class X DY //Weshalb kommt hier erst der Destruktor von Y ? DX // ICh schätze mal die beiden DX killen die beiden KX am Anfang DX KX // hier beginnt die Instanz der Klasse X x ? KX KY KX // Ende von der Instanz Xx ? KZ KX KX KY KX // gleiche Frage wie oben. Warum kommt hier nochmal der Konstruktor von X KZ
-
vatan89 schrieb:
KX //Durch das X x [2][1] wird das KX zweimal ausgegeben KX // KY //Anschließend tritt der Konstruktor von Class Y KX //und von der Class X DX // Destruktor von Class X DY //Weshalb kommt hier erst der Destruktor von Y ? DX // ICh schätze mal die beiden DX killen die beiden KX am Anfang DX KX // hier beginnt die Instanz der Klasse X x ? KX KY KX // Ende von der Instanz Xx ? KZ KX KX KY KX // gleiche Frage wie oben. Warum kommt hier nochmal der Konstruktor von X KZAufräumen geschieht genau umgekehrt wie das Erstellen.
int main() { { Y y;Ein Y wird erstellt. Es enthält 2 X. Als Member werden diese zuerst erstellt:
KX KXDann der Rest vom Y selbst:
KYX x;Ein X wird erstellt:
KX}Ende des Scopes, das Y und das X werden zerstört. Zuerst das X:
DXDann das Y:
DYDann die beiden X, die Member von Y sind:
DX DXZ*ZPtr= new Z [2];Zwei Z werden erzeugt. Nacheinander. Jedes Z enthält ein Y und ein X (das Y zuerst, da es weiter oben steht). Das Y wieder zwei X. Also zuerst wird das Y erzeugt, dazu werden zuerst zwei X erzeugt:
KX KXDann das Y selbst:
KYDann das X als zweiter Member des Z:
KXDann das Z selbst:
KZann das gleiche noch einmal für das zweite Z:
KX KX KY KX KZPreisfrage, ob du es auch verstanden hast: Wie sähe die Ausgabe bei einem anschließenden
delete[] ZPtr;aus? (Mit Erklärung, nicht einfach ausprobieren!)
-
poah Wahnsinn danke Leute, echt. Hab's jetzt endlich kapiert *schwere Geburt*

Also zur Preisfrage:
Wenn ich den Pointer Kille :
DZ DX DY DX DX DZ DX DY DX DX???? so in der Art
-
Fast. y wird in Z zuerst deklariert, also auch zuerst zerstört.
Tauscch die Zerstörung von y und x aus, dann stimmt's.
-
Ethon schrieb:
Fast. y wird in Z zuerst deklariert, also auch zuerst zerstört.
Tauscch die Zerstörung von y und x aus, dann stimmt's.Nein, gerade aus diesem Grund ist es so wie vatan89 richtig gesagt hat.
-
Ethon schrieb:
Fast. y wird in Z zuerst deklariert, also
auch zuerst zerstört.zuletzt zerstört.
Zerstört wird immer in der umgekehrten Reihenfolge wie aufgebaut wurde.
-
Grrr, in letzter Zeit häufen sich Griffe ins Klo bei mir. Vor allem wenn ich eigentlich wüsste wie es richtig ist.
Ich schiebe es mal auf Müdigkeit beim Erstellen des Posts und entschuldige mich für eventuell entstandene Verwirrung.
-
Leute hab grad die Klausur hinter mir und dazu eine dringende Frage, was ich unbedingt wissen muss:
In der Aufgabe kam sowas ähnliches wie ich hier schon gepostet habe.
es sah in der Form aus, solang es noch frisch ist:
3- Klassen jeweils x,y,z
f1(....)
{ Z = new y} // oder so ähnlich, aufjedenfall ein new Objektint main () { Y y; // so in der Form die Funktion f1 wurde in der Klasse beschrieben f1(y); }Meine Frage, befindet sich das f1(y) noch im Scope ? sprich wenn ich die Konstruktoren erzeuge.
KX | KX | gehören alle dem Objekt Yy KY | KX |werden diese vor dem übergang zu f1(y) zerstört oder erst nach der ausführung des von f1(y) bzw des new y ?
falls ich es etwas unklar formuliert habe, entschuldigt dies bitte es ist nur eine wage beschreiben. Ich hatte eine wahl zwischen
KX KX KX KX KY KY KX KX KZ oder KZ KX DZ KX DX KY DY KX DX KZ DX DZ KX DX KX DY KY DX KX DX KZich habe dummerweise das linke gewählt, weil ich dachte, dass zuerst new noch erstellt wird und dann das objekt von oben zerstört wird. Aber ich denke dass das rechte richtig ist.
Findet nacht der main die zerstörung vor dem new statt oder erst nachdem new erstellt wurde ?
-
Der Scope endet mit der schließenden Klammer. Zu dem Zeitpunkt werden auch die lokalen Variablen zerstört.
Eine Funktion hat ihren eigenen Scope. Du kannst es dir so vorstellen, dass der Rumpf der Funktion an der Stelle des Aufrufs eingefügt wird (was bei inline-Methoden tatsächlich der Fall ist)
Also sind bezüglich der Objekt-Lebensdauer äquivalent:
f() { X x = new X; } int main() { Y y; f(); }und
int main() { Y y; { X* x = new X; } }Da das innere x aber nicht zerstört wird, ist es eigentlich auch egal, wie lange es genau lebt

-
Ein Scope wird verlassen, wenn seine geschweifte Klammer geschlossen wird:
{ Y y; // Code { // Code { // usw. } // interessiert y nicht die Bohne // Code } // interessiert y nicht die Bohne // Code } // Hier stirbt y.Dazwischen mag stehen was will. Selbstverständlich auch Funktionsaufrufe. Auch bei einer Exception würde y erst an der beschriebenen Stelle zerstört. Ebenso bei einem goto, break oder ähnlichem aus dem Scope heraus. Einzig solch gefürchtete Mittel wie exit, abort, longjmp & Co. können den Scope verlassen, ohne dass ein Destruktor aufgerufen wird (und sind daher zu vermeiden, wenn man nicht ganz genau weiß, was man tut).
daddy_felix schrieb:
int main() { Y y; { X* x = new X; } }Da das innere x aber nicht zerstört wird, ist es eigentlich auch egal, wie lange es genau lebt

Das x wird schon zerstört. Aber x ist hier ein roher Pointer und sein Pointee bekommt davon nichts mit. Das mit new erzeugte Objekt existiert also immer noch und ist nicht mehr erreichbar. Typisches Anfängerspeicherloch, wie bei bisher jedem Code den vatan89 uns von seinem Lehrer gezeigt hat.
-
also ist die rechte Variante richtig ? Da lag ich mit der linken wohl wieder voll auf dem Holzweg...wo soll das nur enden mit mir
-
vatan89 schrieb:
also ist die rechte Variante richtig ?
Nein, alles ist falsch. Oder wahrscheinlicher: Du erinnerst dich falsch an die Aufgabenstellung.
-
SeppJ schrieb:
Typisches Anfängerspeicherloch, wie bei bisher jedem Code den vatan89 uns von seinem Lehrer gezeigt hat.
Wobei ich das in diesem Fall durchaus für Absicht halte. Es geht darum, zu erkennen, wann (und ob) Destruktoren aufgerufen werden. Da ist so ein einzelnes new natürlich ein fieser Trick.
Wesentlich interessanter (und realitätsnäher) wäre die Aufgabe natürlich mit Smart Pointern

-
ja ich habe ein sehr schlechtes Gedächtnis :S
aber in dem moment kam es mir halt logisch vor dass die destruktoren von
Y y;
erst nach der Ausführung von
f1(new) kommen. Weil die sich ja in der gleichen Klammer befinden {} kein plan
-
vatan89 schrieb:
aber in dem moment kam es mir halt logisch vor dass die destruktoren von
Y y;
erst nach der Ausführung von
f1(new) kommen.
ist ja auch richtig so. Was wäre sonst mit diesem Code:
{ Y y; f(); y.DoSomething(); }
-
wenn das richtig ist gibts erstmal Freibier von mir auf dem Campus