Allgemeine Fragen zu verschiedenen Themen
-
Hallo, Ich habe allgemein ein paar Fragen, könnt ihr mir helfen diese zu beantworten? bzw. zu berichtigen?
Wofür verwendet man Initialisierungslisten?
Eine Initialisierungsliste sieht z.b so aus:
bruch::bruch()***:zaehler(za),nenner(ne)***{}Man verwendet sie zum übergeben von Parametern, die Initialisierungsliste ist besser als einen normale Initialisierung im {}, da weniger Speicherplatz belegt wird, und der Vorgang schneller von statten geht.
Warum muss beim Kopierkonstruktor der Parameter als Referenz übergeben werden?
Der Parameter muss als Referenz übergeben werden da, der Kopierkonstrukor selbst auch eine Funktion ist.
Das bedeutet wenn man einen Parameter ohne Referenz übergeben würde z.b so bruch(const bruch b); dann würde erneut der Kopierkonstruktor aufgerufen werden und wieder und wieder -> Endlosschleife!!**
Warum nimmt man zum Überladen des Ausgabeoperators << keine Elementfunktion, sondern eine friend-Funktion?
Bitte erklären sie den Grund.**Man nimmt eine Friendfunktion damit man den überladenen Ausgabeoperator auch für andere Klassen verwenden kann, ansonsten (bei Elementfunktion) könnte man diesen nur innerhalb der Klasse benutzen indem dieser deklariert und definiert wurde.
Ist das alles so richtig? Habe ich Informationen vergessen? Bitte schreibt eure Meinung dazu.
vielen dank
-
The architect schrieb:
Wofür verwendet man Initialisierungslisten?
Eine Initialisierungsliste sieht z.b so aus:
bruch::bruch()***:zaehler(za),nenner(ne)***{}Man verwendet sie zum übergeben von Parametern, die Initialisierungsliste ist besser als einen normale Initialisierung im {}, da weniger Speicherplatz belegt wird, und der Vorgang schneller von statten geht.
Initialisierungslisten haben nichts mit der Übergabe von Parametern zu tun. Sie dienen dazu, Member zu initialisieren. Wenn man die Elemente im Konstruktorrumpf initialisiert, kommt es bei Klassen zuerst zu einer Standardkonstruktion und einer anschliessenden Zuweisung. Die Initialisierungsliste kann schneller sein, mit Speicherplatz hat es allerdings nichts zu tun. Bei einigen Typen (konstante Variablen, Referenzen) ist die Initialisierungsliste sogar die einzige Möglichkeit.
The architect schrieb:
Warum muss beim Kopierkonstruktor der Parameter als Referenz übergeben werden?
Der Parameter muss als Referenz übergeben werden da, der Kopierkonstrukor selbst auch eine Funktion ist.
Das bedeutet wenn man einen Parameter ohne Referenz übergeben würde z.b so bruch(const bruch b); dann würde erneut der Kopierkonstruktor aufgerufen werden und wieder und wieder -> Endlosschleife!!Richtig.
The architect schrieb:
Warum nimmt man zum Überladen des Ausgabeoperators << keine Elementfunktion, sondern eine friend-Funktion?
Bitte erklären sie den Grund.Man nimmt eine Friendfunktion damit man den überladenen Ausgabeoperator auch für andere Klassen verwenden kann, ansonsten (bei Elementfunktion) könnte man diesen nur innerhalb der Klasse benutzen indem dieser deklariert und definiert wurde.
Du beschreibst es ein wenig ungenau. Man kann den
ostream::operator<<nicht als Memberfunktion implementieren, da der erste Parameter implizit die Klasse selbst ist. Und da manstd::ostreamnicht nachträglich abändern kann, ist nur eine freie Funktion mit zwei Argumenten (erstes vom Typstd::ostream&) mögich.
-
Vielen dank Nexus!
Hier hätte ich noch ein paar Fragen an euch:
Die meisten Operatoren können als Elementfunktion einer Klasse oder als externe Funktion (befreundet oder normal) überladen werden.
Worin besteht der Unterschied?Elementfunktionen gelten nur in der Klasse in der sie deklariert und defininiert sind.
Externe Funktionen (auch Globale Funktionen bezeichnet)
Können befreundet aus der Sicht der Klasse sein. Auf diese Funktionen können alle Klassen zugreifen bei denen sie als befreundet deklariert sind.
Einfach ein friend vor den Prototyp setzten z.b so friend bruch operator+= (bruch b);mehr ist mir dazu leider nicht eingefallen.
Warum ist die Zuweisung von Klassenobjekten mit operator=(..) aufwendiger als die Initialisierung mit dem Kopierkonstruktor?
Mit dem Kopierkonstruktor wird z.b ein Klassenobjekt so erschaffen und initialisiert:
bruch a; // steht hier nur damit davor schon bekannt bruch b(a);Die Deklaration des Kopierkonstruktors sieht wie folgt aus:
bruch::bruch(const bruch& b);Mit dem operator=(..) muss bei einer Initialisierung überprüft werden ob links und rechts vom = der selbe wert steht.
if(this==&b)return *this;Die Deklaration des operator= sieht wie folgt aus:
bruch bruch::operator= (bruch b);Man kann den unterschied erkennen wenn man sich die beiden Deklarationen näher anschaut.
Beim Kopierkonstruktor wird und muss eine Referenz übergeben werden, beim operator= wird das Objekt übergeben, das bedeutet die Funktion macht eine Kopie von dem Objekt um es in dem Operator= ( der ja auch nur wie eine normale Funktion ist) zu verwenden.
Anschließend muss aus diesem Grund *this zureückgegeben werden.Der Kopierkonstruktor hat somit keinen Rückgabewert, der operator= hat einen.
Deshalb würde ich sagen ist der Kopierkonstrukor schneller aber nicht so angenehm zu schreiben als mit dem überladenen operator=.
-
Beim 2. durchlesen ist mir aufgefallen das ich hier einen Fehler gemacht habe:
Auf diese Funktionen können alle Klassen zugreifen bei denen sie als befreundet deklariert sind.
Einfach ein friend vor den Prototyp setzten z.b so friend bruch operator+= (bruch b);Es müsste heissen, Alle Funktionen die als befreundet in einer Klasse deklariert sind, sind befugt auf Klassenmember zuzugreifen.
Einfach ein friend vor den Prototyp setzten z.b so friend bruch operator+= (bruch b);
-
Die meisten Operatoren können als Elementfunktion einer Klasse oder als externe Funktion (befreundet oder normal) überladen werden.
Worin besteht der Unterschied?Mal eine kleine Aufgabe, nachder du wahrscheinlich den Unterschied bemerken wirst:
Schreibe eine beliebige Klasse, die einen Operator + so zur Verfügung steht, dass das hier möglich ist:MyClass m; int i; i + m;Probier das mal als Elementfunktion und als Funktion zu schreiben.
Elementfunktionen gelten nur in der Klasse in der sie deklariert und defininiert sind.
Externe Funktionen (auch Globale Funktionen bezeichnet)
Können befreundet aus der Sicht der Klasse sein. Auf diese Funktionen können alle Klassen zugreifen bei denen sie als befreundet deklariert sind.
Einfach ein friend vor den Prototyp setzten z.b so friend bruch operator+= (bruch b);Eigentlich sind deine "externe" Funktionen einfach nur "Funktion" genannt. Global müssen sie nicht einmal sein. Sie können auch in einem Namespace gepackt sein.
Operator += ist ein Beispiel, das eher als Elementfunktion implementiert wird, da es ja zu dem Objekt gehört und es verändert.
Warum ist die Zuweisung von Klassenobjekten mit operator=(..) aufwendiger als die Initialisierung mit dem Kopierkonstruktor?
Ich verstehe nicht ganz, auf was du weiter unten im Text hinaus willst, aber grundsätzlich ist das Problem ja, dass das Objekt bereits initialisiert ist.
Üblicherweise wird auch bei dem Kopierkonstruktor eine const Referenz übregeben. Bei deinem Beispiel müsse nichteinmal auf Gleichheit geprüft werden, da durch Kopie ja bestimmt ein neues Objekt erstellt wird.
Nun normalerweise wird der Kopierkonstruktor mit dem Copy&Swap Idom geschrieben, sprich es wird eine Kopie erstellt (mit rechts-Objekt als Kopierkonstruktorparameter) und dann mit dem eigentlichen Objekt jeder Wert einfach getauscht. Das temporäre Objekt wird schlussendlich wieder gelöscht. (Lebt ja nur innerhalb der Funktion).