018
31.07.2003, 08:53 Uhr
virtual
Sexiest Bit alive (Operator)
|
Zunächstmal was zu den Begrifflichkeiten:
Ist eine Deklaration.
Ist eine Definition; wenn vorher im Quelltext keine Deklaration gefunden wurde, ist es auch die Deklaration.
Bei unserem ctor handelt es sich also um einen Deklaration und eine Definition, weil da das Semikolon nach dem schliessenden Klammer der parameterliste fehlt und "irgendwas" anderes kommt. Obigen ctor hätte man auch so schreiben können:
C++: |
move(DIRECTION d_, int n_ = 1) { d = d_; n = n_; }
|
Nun gibt es speziell beim Ctor ja die Situation, daß man bestimmte Sachen initialisieren muß, bevor man in den Body vom ctor ("{...}") eintritt. zB bei einer abgeleiteten Klasse die Basisklasse:
C++: |
class Base { public: Base(int x);
};
class Derived: public Base { public: Derived(int x) :Base(x) { /*Hier muß der Base anteil bereits initialisiert sein */ } };
|
Anders als in Java (da gibt es mit "super" die Möglichkeit, den Anteil von Base an beliebiger Stelle im ctor von Derived zu initialisieren) muß in C++ der Anteil von Base initialisiert sein, bevor in den Body vom Ctor gesprungen wird.Das wird von dem Initialisierer erledigt, also dem ":Base(x)". Es gibt folgende Situationen, wo man mit Initialisieren arbeiten muß: 1. Bei Ableitungen (siehe oben) zum initialisieren der Basisklasse 2. Wenn die Klasse Referenzen enthält, müssen die Referenzen ebenfalls vor Eintritt in den Body vom ctor initialisiert werden. 3. Wenn die Klasse eine Aggregation von anderen Klassen ist, die keinen Defaultconstructor bereitstellen (Fall 2 ist so gesehen ein Spezialfall von diesem).
Man kann generell sagen, daß man alle Attribute eine ctor mit Initialisierern initialisieren kann und (wie im move Beispiel) einen leeren Body hat. Das macht vor allem dann sinn, wenn man andere, kompliziert zu konstruierende Objekte als Membervariablen hat. Beispiel:
C++: |
class Bad { std::string x; public: Bad(const std::string& x_) { x = x_; } };
class Good { std::string x; public: Good(const std::string& x_) :x(x_) { } };
|
Sowohl die Klasse Goood alsauch die Klasse Bad sind rein C++ technisch okay (es sei denn, ich habe mich vertippt), allerdings tun sie zwei recht unterschiedliche Dinge im Ctor: Bad Unternimmt im ctor folgende Schritte: 1. Es ruft den Default-ctor für Bad::x (ein std::string) auf 2. Es ruft den Zuweisungsoperator von std::string auf, weil ja im Body eine Zuweisung stattfindet. 3. Der Zuweisungoperator wird - wenn er Exceptionsicher geschrieben sein will, in der Regel die Contruction eines weiteres temp. string objektes nach sich ziehen Good hingegen macht genau einen Schritt: 1. Es ruft den Copy-Constructor für Good::x auf.
Generell kann man also sagen, daß die Verwendung von Initialisieren die Performance begünstigen, in einigen Situation sogar zwingend erforderlich sind. -- Gruß, virtual Quote of the Month Ich eß' nur was ein Gesicht hat (Creme 21) |