Warum muss der Parameter eines Kopierkonstruktors als Referenz übergeben werden?
Warum sollte der Kopierkonstruktor seinen Parameter als Referenz in C++ akzeptieren?
Joni
GManNickG
Denn wenn es nicht als Referenz gilt, dann als Wert. Dazu erstellen Sie eine Kopie und rufen dazu den Kopierkonstruktor auf. Aber dazu müssen wir einen neuen Wert erstellen, also rufen wir den Kopierkonstruktor auf und so weiter …
(Sie hätten eine unendliche Rekursion, weil “um eine Kopie zu erstellen, müssen Sie eine Kopie erstellen”.)
-
Gibt es einen Grund, warum es kein Pass-by-Pointer zur Instanz sein könnte?
– Barry Wark
21. April 2010 um 20:52 Uhr
-
Dann ist es kein Kopierkonstruktor mehr, sondern nur ein normaler alter Konstruktor, der zufällig einen Zeiger akzeptiert.
– Dennis Zickefoose
21. April 2010 um 21:01 Uhr
-
@Barry Sie implementieren normalerweise einen Kopierkonstruktor, wenn der Compiler versucht, durch Aufrufen selbst eine Kopie eines Objekts zu erstellen
object o(other_object)
. Das funktioniert aber nur, wennobject
hat einen Konstruktor, der einen anderen akzeptiertobject
nach Wert oder Referenz. Sie wissen bereits, warum die Wertübergabe nicht funktioniert, daher ist die Übergabe per Referenz oder const-Referenz die einzige Möglichkeit. Wenn Ihr “Kopierkonstruktor” einen Zeiger auf eine nehmen würdeobject
dann müsste der Code des Compilers seinobject o(&other_object)
. Im Wesentlichen schreiben Sie also einen Konstruktor, der erfüllt, was der Compiler und die Benutzer erwarten.– wilhelmtel
21. April 2010 um 23:46 Uhr
-
Ja, das macht absolut Sinn. Danke.
– Barry Wark
22. April 2010 um 4:41 Uhr
-
Ein weiterer guter Grund, der von meinem Compiler festgestellt wurde, ist, dass bei einer Basisklasse mit rein virtuellen Funktionen die Initialisierung dieser Variablen nach Wert nicht möglich wäre
– Benutzer451498
14. Mai 2012 um 23:52 Uhr
Weil Wertübergabe den Kopierkonstruktor aufrufen würde 🙂
Kartoffelklatsche
Die Alternative zur Referenzübergabe ist die Wertübergabe. Pass-by-Value ist wirklich Pass-by-Copy. Der Kopierkonstruktor wird benötigt, um eine Kopie zu erstellen.
Wenn Sie eine Kopie erstellen müssten, nur um den Kopierkonstruktor aufzurufen, wäre dies ein Rätsel.
(Ich denke, die unendliche Rekursion würde im Compiler auftreten und Sie würden niemals ein solches Programm erhalten.)
neben rational Gründen ist es laut Standard in §12.8/3 verboten:
Eine Deklaration eines Konstruktors für eine Klasse X ist schlecht formatiert, wenn ihr erster Parameter vom Typ (optional CV-qualifiziert) X ist und entweder keine anderen Parameter vorhanden sind oder alle anderen Parameter Standardargumente haben.
-
Compiler können gerne unendliche Rekursion ausspucken; Ich vermute, das ist kein Sonderfall. Das Programm ist jedoch falsch formatiert, wenn Sie einen Kopierkonstruktor mit einem Nichtreferenzparameter deklarieren. Sie haben also Recht, dass es nicht kompilieren sollte.
– Dennis Zickefoose
21. April 2010 um 20:09 Uhr
-
@Dennis: Ich meine, wenn Sie versuchten, ein solches Programm zu kompilieren, würde der Compiler beim Versuch, den Code zu generieren, hängen bleiben. Es würde keine rekursive Funktion generieren, da das Rätsel vor dem Funktionsaufruf im Aufrufer auftritt.
– Kartoffelklatsche
21. April 2010 um 20:55 Uhr
-
In jedem Fall ist das Programm schlecht geformt, egal ob Sie versuchen, es zu verwenden oder nicht. Das einfache Definieren des Konstruktors reicht aus, damit der Compiler Sie anschreit.
– Dennis Zickefoose
21. April 2010 um 21:04 Uhr
-
@Dennis: In der Tat, obwohl das einfach eine Regel ist.
– Kartoffelklatsche
21. April 2010 um 21:18 Uhr
Es wäre unendlich rekursiv, wenn Sie es als Wert übergeben würden
Sriraman
Immer wenn Sie eine Funktion aufrufen (Beispiel: int f(car c)), deren Argumente andere als die eingebauten Datentypen (hier car) sind, muss das tatsächliche Objekt, das vom Aufrufer bereitgestellt wird, in die Variable im Parameter der aufgerufenen Funktion kopiert werden.
Beispiel:
car carobj;
f(carobj);
das heißt kopieren carobj
zu c
.
carobj
muss in den Parameter kopiert werden c
in Funktion f
.
Um das Kopieren zu erreichen, wird der Kopierkonstruktor aufgerufen.
In diesem Fall Funktion f
aufgerufen mit Wertübergabe oder mit anderen Worten, Funktion f
wird deklariert, um als Wert übergeben zu werden.
Wenn Funktion f
nimmt als Referenz über, dann ist seine Deklaration
int f(car &c);
In diesem Fall,
car carobj;
f(carobj);
benötigt keinen Kopierkonstruktor.
In diesem Fall, c
wird zum Alias von carobj
.
Anhand der beiden oben genannten Szenarien fasse ich sie der Übersichtlichkeit halber wie folgt zusammen:
-
Wenn eine Funktion deklariert wird, um einen Parameter als Wert eines Objekts zu übernehmen, wird der Kopierkonstruktor des Objekts aufgerufen.
-
Wenn eine Funktion so deklariert ist, dass sie einen Parameter als “Übergabe durch Referenz” akzeptiert, wird der Parameter zu einem Alias des vom Aufrufer bereitgestellten Objekts. Kein Kopierkonstruktor erforderlich!
Nun stellt sich die Frage, warum eine Referenzübergabe erforderlich ist. Wenn der Kopierkonstruktor eine Referenz akzeptiert, wird die empfangende Variable zu einem Alias des bereitgestellten Objekts. Daher muss der Kopierkonstruktor (in diesem Fall kein Aufruf an sich selbst) den Wert im vom Aufrufer bereitgestellten Objekt kopieren, um die Variable des Konstruktors in der Argumentliste zu kopieren.
Andernfalls, wenn der Kopierkonstruktor das vom Aufrufer gelieferte Objekt als Wert nimmt, dh als Wert übergeben wird, dann benötigt er den Kopierkonstruktor des gegebenen Objekts; Um also das vom Aufrufer gelieferte Objekt in unsere Funktion selbst (in diesem Fall den Kopierkonstruktor) zu bekommen, müssen wir den Kopierkonstruktor aufrufen, was nichts anderes ist, als dieselbe Funktion während der Funktionsdeklaration aufzurufen.
Das ist der Grund für die Übergabe einer Referenz an einen Kopierkonstruktor.
-
Sie haben zwar Recht, aber es gab bereits vier Antworten, die dies erklärten, und zwar viel klarer. Ich verstehe nicht, warum Sie dachten, eine fünfte Antwort auf diese Frage wäre hilfreich.
– Ben Voigt
13. März 2012 um 0:32 Uhr
Anand Tripathi
Es ist notwendig, das Objekt als Referenz und nicht als Wert zu übergeben, denn wenn Sie es als Wert übergeben, wird seine Kopie mit dem Kopierkonstruktor erstellt. Dies bedeutet, dass der Kopierkonstruktor sich selbst aufrufen würde, um eine Kopie zu erstellen. Dieser Prozess wird fortgesetzt, bis der Compiler abgelaufen ist der Erinnerung.
-
Sie haben zwar Recht, aber es gab bereits vier Antworten, die dies erklärten, und zwar viel klarer. Ich verstehe nicht, warum Sie dachten, eine fünfte Antwort auf diese Frage wäre hilfreich.
– Ben Voigt
13. März 2012 um 0:32 Uhr
Dalbir Singh
Es ist sehr wichtig, Objekte als Referenz zu übergeben. Wenn dem Kopierkonstruktor ein Objekt als Wert übergeben wird, würde sich sein Kopierkonstruktor selbst aufrufen, um den eigentlichen Parameter in den Formalparameter zu kopieren. Somit wird eine endlose Aufrufkette an den Kopierkonstruktor initiiert. Dieser Vorgang würde fortgesetzt, bis dem System der Speicher ausgeht.
Daher sollte in einem Kopierkonstruktor der Parameter immer als Referenz übergeben werden.