Auf- und Abbau eines Objekts
Content |
Diese Sitzung dient der Beschäftigung mit den speziellen Methoden einer Klasse. Dies sind Methoden, die implizit vom Übersetzer benutzt werden und auch unter bestimmten Bedingungen vom Übersetzer selbst erzeugt werden.
Default Constructor
Beginnen wir mit den Konstruktoren. Es gibt den sogenannten default constructor ohne Parameter, der durch den Übersetzer gestellt wird, wenn alle nicht-statischen Variablen-Komponenten der Klasse ohne Parameter (also mit default constructor) konstruierbar sind und kein einziger Konstruktor angegeben wird.
Der durch den Übersetzer erzeugte default constructor konstruiert alle nicht-statischen Variablen-Komponenten in der deklarierten Reihenfolge. Da bei den elementaren Datentypen keine Initialisierung erfolgt, kann hier nur etwas anfallen, wenn nicht-triviale Variablen dabei sind. Folgendes Beispiel möge dies demonstrieren:
#include <iostream> class X { public: X() { std::cout << "an object of type X gets default-constructed" << std::endl; } }; class Y { public: Y() { std::cout << "an object of type Y gets default-constructed" << std::endl; } }; class Z { /* no explicit default constructor */ X x; Y y; }; int main() { Z z; /* invokes compiler-provided default constructor */ }
theon$ g++ -Wall -o default-constructors default-constructors.cpp theon$ ./default-constructors an object of type X gets default-constructed an object of type Y gets default-constructed theon$
In diesem Beispiel hat die Klasse Z überhaupt keinen Konstruktor. Somit wurde ein default constructor durch den Übersetzer erzeugt, der nacheinander x und y konstruiert. Bei X und Y ist jeweils ein expliziter default constructor gegeben, der eine Ausgabe erzeugt. An der Ausgabe lässt sich nachvollziehen, dass zuerst x initialisiert wird und erst danach y.
Und selbst wenn ein expliziter default constructor gestellt wird, so werden alle in ihm nicht explizit konstruierten nicht-statischen Variablenkomponenten implizit konstruiert mit dem default constructor, falls vorhanden.
Destructor
Sofern eine Klasse nicht-trivial ist, d.h. mindestens eine nicht-statische Variable enthält, bei denen eine explizite Abbau-Operation erforderlich ist, wird durch den Übersetzer ein destructor hinzugefügt, der sich darum kümmert. Wenn ein destructor explizit deklariert wird, wird der entsprechende Programmtext beim Abbau ausgeführt, bevor der vom Übersetzer generierte destructor zum Zuge kommt.
Der Abbau erfolgt in umgekehrter Reihenfolge, d.h. die zuletzt deklarierte nicht-statische Variablenkomponente kommt zuerst.
Folgendes Beispiel demonstriert die Reihenfolge beim Auf- und Abbau:
#include <iostream> class X { public: X() { std::cout << "an object of type X gets default-constructed" << std::endl; } ~X() { std::cout << "an object of type X gets destructed" << std::endl; } }; class Y { public: Y() { std::cout << "an object of type Y gets default-constructed" << std::endl; } ~Y() { std::cout << "an object of type Y gets destructed" << std::endl; } }; class Z { public: Z() { std::cout << "an object of type Z gets default-constructed" << std::endl; } ~Z() { std::cout << "an object of type Z gets destructed" << std::endl; } private: X x; Y y; }; int main() { Z z; /* invokes compiler-provided default constructor */ }
theon$ g++ -Wall -o destructors destructors.cpp theon$ ./destructors an object of type X gets default-constructed an object of type Y gets default-constructed an object of type Z gets default-constructed an object of type Z gets destructed an object of type Y gets destructed an object of type X gets destructed theon$
Fragen
Denken Sie über die folgenden Fragen in Ruhe nach und notieren Sie sich die Antwort auf Papier, bevor Sie die Antworten auf der folgenden Seite einsehen. Bitte lassen Sie die Fragen nicht durch den Übersetzer beantworten.
-
Ist folgendes zulässig?
class X { X(int) {}; // Konstruktor mit einer ganzen Zahl, die ignoriert wird }; class Y { X x; }; Y y;
-
Ist folgendes zulässig und falls ja, welche Ausgabe ist dann zu erwarten?
#include <iostream> class X { public: X() { std::cout << "X constructed" << std::endl; } }; class Y { public: Y() { std::cout << "Y constructed" << std::endl; } }; class Z { public: Z() : y(), x() {} private: X x; Y y; }; int main() { Z z; }
-
Ist folgendes zulässig? Falls nein, wie könnte es korrigiert werden?
class X { const int i; }; X x;
-
Was gibt folgendes Programm aus?
#include <iostream> class X { public: X() { std::cout << "X constructed" << std::endl; } ~X() { std::cout << "X destructed" << std::endl; } }; class Y { X x; public: Y() { std::cout << "Y constructed" << std::endl; } ~Y() { std::cout << "Y destructed" << std::endl; } }; class Z { Y y; public: Z() { std::cout << "Z constructed" << std::endl; } ~Z() { std::cout << "Z destructed" << std::endl; } }; int main() { X x; Y y; Z z; }