logo

Kopieren Sie den Konstruktor in C++

Voraussetzung: Konstruktor in C++

A Konstruktor kopieren ist eine Memberfunktion, die ein Objekt mithilfe eines anderen Objekts derselben Klasse initialisiert. Vereinfacht ausgedrückt wird ein Konstruktor, der ein Objekt erstellt, indem er es mit einem zuvor erstellten Objekt derselben Klasse initialisiert, als a bezeichnet Konstruktor kopieren .



Der Kopierkonstruktor wird verwendet, um die Mitglieder eines neu erstellten Objekts zu initialisieren, indem die Mitglieder eines bereits vorhandenen Objekts kopiert werden.

Der Kopierkonstruktor akzeptiert einen Verweis auf ein Objekt derselben Klasse als Argument.

Sample(Sample &t) { id=t.id; }>

Der Prozess der Initialisierung von Mitgliedern eines Objekts durch einen Kopierkonstruktor wird als Kopierinitialisierung bezeichnet.



Dies wird auch als mitgliedweise Initialisierung bezeichnet, da der Kopierkonstruktor ein Objekt mit dem vorhandenen Objekt initialisiert, wobei beide zur gleichen Klasse gehören, und zwar auf der Basis einer Kopie von Mitglied zu Mitglied.

Der Kopierkonstruktor kann vom Programmierer explizit definiert werden. Wenn der Programmierer den Kopierkonstruktor nicht definiert, übernimmt der Compiler dies für uns.

Beispiel:



Android-Telefon-Einstellungsmenü
Syntax des Kopierkonstruktors mit Beispiel

Syntax des Kopierkonstruktors

C++




#include> #include> using> namespace> std;> class> student {> >int> rno;> >char> name[50];> >double> fee;> public>:> >student(>int>,>char>[],>double>);> >student(student& t)>// copy constructor> >{> >rno = t.rno;> >strcpy>(name, t.name);> >fee = t.fee;> >}> >void> display();> };> student::student(>int> no,>char> n[],>double> f)> {> >rno = no;> >strcpy>(name, n);> >fee = f;> }> void> student::display()> {> >cout << endl << rno <<>' '> << name <<>' '> << fee;> }> int> main()> {> >student s(1001,>'Manjeet'>, 10000);> >s.display();> >student manjeet(s);>// copy constructor called> >manjeet.display();> >return> 0;> }>

>

>

Ausgabe

 1001 Manjeet 10000 1001 Manjeet 10000>

C++




#include> #include> using> namespace> std;> class> student {> >int> rno;> >char> name[50];> >double> fee;> public>:> >student(>int>,>char>[],>double>);> >student(student& t)>// copy constructor (member wise> >// initialization)> >{> >rno = t.rno;> >strcpy>(name, t.name);> >}> >void> display();> >void> disp() { cout << endl << rno <<>' '> << name; }> };> student::student(>int> no,>char> n[],>double> f)> {> >rno = no;> >strcpy>(name, n);> >fee = f;> }> void> student::display()> {> >cout << endl << rno <<>' '> << name <<>' '> << fee;> }> int> main()> {> >student s(1001,>'Manjeet'>, 10000);> >s.display();> >student manjeet(s);>// copy constructor called> >manjeet.disp();> >return> 0;> }>

>

>

Ausgabe

 1001 Manjeet 10000 1001 Manjeet>

Eigenschaften des Kopierkonstruktors

1. Der Kopierkonstruktor wird verwendet, um die Mitglieder eines neu erstellten Objekts zu initialisieren, indem die Mitglieder eines bereits vorhandenen Objekts kopiert werden.

2. Der Kopierkonstruktor akzeptiert einen Verweis auf ein Objekt derselben Klasse als Argument. Wenn Sie das Objekt im Kopierkonstruktor als Wert übergeben, würde dies zu einem rekursiven Aufruf des Kopierkonstruktors selbst führen. Dies liegt daran, dass bei der Übergabe eines Werts eine Kopie erstellt werden muss und beim Erstellen einer Kopie der Kopierkonstruktor aufgerufen werden muss, was zu einer Endlosschleife führt. Durch die Verwendung einer Referenz wird diese Rekursion vermieden. Deshalb verwenden wir Referenzen auf Objekte, um unendliche Aufrufe zu vermeiden.

Sample(Sample &t) { id=t.id; }>

3. Der Prozess der Initialisierung von Mitgliedern eines Objekts durch einen Kopierkonstruktor wird als bezeichnet Initialisierung kopieren.

4 . Dies wird auch als mitgliedweise Initialisierung bezeichnet, da der Kopierkonstruktor ein Objekt mit dem vorhandenen Objekt initialisiert, wobei beide zur gleichen Klasse gehören, und zwar auf der Basis einer Kopie für jedes Mitglied.

5. Der Kopierkonstruktor kann vom Programmierer explizit definiert werden. Wenn der Programmierer den Kopierkonstruktor nicht definiert, übernimmt der Compiler dies für uns.

Beispiel:

C++




// C++ program to demonstrate the working> // of a COPY CONSTRUCTOR> #include> using> namespace> std;> class> Point {> private>:> >int> x, y;> public>:> >Point(>int> x1,>int> y1)> >{> >x = x1;> >y = y1;> >}> >// Copy constructor> >Point(>const> Point& p1)> >{> >x = p1.x;> >y = p1.y;> >}> >int> getX() {>return> x; }> >int> getY() {>return> y; }> };> int> main()> {> >Point p1(10, 15);>// Normal constructor is called here> >Point p2 = p1;>// Copy constructor is called here> >// Let us access values assigned by constructors> >cout <<>'p1.x = '> << p1.getX()> ><<>', p1.y = '> << p1.getY();> >cout <<>' p2.x = '> << p2.getX()> ><<>', p2.y = '> << p2.getY();> >return> 0;> }>

>

>

Ausgabe

p1.x = 10, p1.y = 15 p2.x = 10, p2.y = 15>

Arten von Kopierkonstruktoren

1. Standard-Kopierkonstruktor

Ein implizit definierter Kopierkonstruktor kopiert die Basen und Mitglieder eines Objekts in derselben Reihenfolge, in der ein Konstruktor die Basen und Mitglieder des Objekts initialisieren würde.

C++




// Implicit copy constructor Calling> #include> using> namespace> std;> class> Sample {> >int> id;> public>:> >void> init(>int> x) { id = x; }> >void> display() { cout << endl <<>'ID='> << id; }> };> int> main()> {> >Sample obj1;> >obj1.init(10);> >obj1.display();> >// Implicit Copy Constructor Calling> >Sample obj2(obj1);>// or obj2=obj1;> >obj2.display();> >return> 0;> }>

>

Zeichenfolge zu lang

>

Ausgabe

 ID=10 ID=10>

2. Benutzerdefinierter Kopierkonstruktor

Ein benutzerdefinierter Kopierkonstruktor wird im Allgemeinen benötigt, wenn ein Objekt Zeiger oder nicht gemeinsam nutzbare Referenzen besitzt, beispielsweise auf eine Datei. In diesem Fall sollten auch ein Destruktor und ein Zuweisungsoperator geschrieben werden

C++




// Explicitly copy constructor Calling> #include> using> namespace> std;> class> Sample {> >int> id;> public>:> >void> init(>int> x) { id = x; }> >Sample() {}>// default constructor with empty body> >Sample(Sample& t)>// copy constructor> >{> >id = t.id;> >}> >void> display() { cout << endl <<>'ID='> << id; }> };> int> main()> {> >Sample obj1;> >obj1.init(10);> >obj1.display();> >Sample obj2(> >obj1);>// or obj2=obj1; copy constructor called> >obj2.display();> >return> 0;> }>

>

>

xdxd Bedeutung
Ausgabe

 ID=10 ID=10>

C++




// C++ Programt to demonstrate the student details> #include> #include> using> namespace> std;> class> student {> >int> rno;> >string name;> >double> fee;> public>:> >student(>int>, string,>double>);> >student(student& t)>// copy constructor> >{> >rno = t.rno;> >name = t.name;> >fee = t.fee;> >}> >void> display();> };> student::student(>int> no, string n,>double> f)> {> >rno = no;> >name = n;> >fee = f;> }> void> student::display()> {> >cout << endl << rno <<>' '> << name <<>' '> << fee;> }> int> main()> {> >student s(1001,>'Ram'>, 10000);> >s.display();> >student ram(s);>// copy constructor called> >ram.display();> >return> 0;> }>

>

>

Ausgabe

 1001 Ram 10000 1001 Ram 10000>

Wann wird der Kopierkonstruktor aufgerufen?

In C++ kann ein Kopierkonstruktor in den folgenden Fällen aufgerufen werden:

  • Wenn ein Objekt der Klasse als Wert zurückgegeben wird.
  • Wenn ein Objekt der Klasse (an eine Funktion) als Wert als Argument übergeben wird.
  • Wenn ein Objekt basierend auf einem anderen Objekt derselben Klasse erstellt wird.
  • Wenn der Compiler ein temporäres Objekt generiert.

Es ist jedoch nicht garantiert, dass in all diesen Fällen ein Kopierkonstruktor aufgerufen wird, da der C++-Standard es dem Compiler ermöglicht, die Kopie in bestimmten Fällen wegzuoptimieren, ein Beispiel ist der Rückgabewertoptimierung (manchmal auch als RVO bezeichnet).

Elision kopieren

Bei der Kopierelision verhindert der Compiler das Anfertigen zusätzlicher Kopien, was Platz spart und die Programmkomplexität (sowohl Zeit als auch Platz) verbessert. Dadurch wird der Code optimierter.

Beispiel:

C++




// C++ program to demonstrate> // the working of copy elision> #include> using> namespace> std;> class> GFG {> public>:> >void> print() { cout <<>' GFG!'>; }> };> int> main()> {> >GFG G;> >for> (>int> i = 0; i <= 2; i++) {> >G.print();> >cout <<>' '>;> >}> >return> 0;> }>

>

>

Ausgabe

 GFG! GFG! GFG!>

Jetzt muss der Compiler entscheiden, was er drucken möchte. Er könnte entweder die obige Ausgabe oder Fall 1 oder Fall 2 unten drucken, und das ist was Rückgabewertoptimierung Ist. In einfachen Worten: RVO ist eine Technik, die dem Compiler zusätzliche Befugnisse gibt, das erstellte temporäre Objekt zu beenden, was zu einer Änderung des beobachtbaren Verhaltens/der beobachtbaren Eigenschaften des endgültigen Programms führt.

Fall 1:

GFG! GFG!>

Fall 2:

GFG!>

Wann wird ein benutzerdefinierter Kopierkonstruktor benötigt?

Wenn wir keinen eigenen Kopierkonstruktor definieren, erstellt der C++-Compiler einen Standardkopierkonstruktor für jede Klasse, der eine mitgliedweise Kopie zwischen Objekten durchführt. Der vom Compiler erstellte Kopierkonstruktor funktioniert im Allgemeinen einwandfrei. Wir müssen unseren eigenen Kopierkonstruktor nur dann definieren, wenn ein Objekt Zeiger oder eine Laufzeitzuordnung der Ressource hat ein Dateihandle , eine Netzwerkverbindung usw.

Der Standard Der Konstruktor führt nur flache Kopien durch.

flache Kopie in C++

Deep Copy ist nur mit einem benutzerdefinierten Kopierkonstruktor möglich. In einem benutzerdefinierten Kopierkonstruktor stellen wir sicher, dass Zeiger (oder Referenzen) kopierter Objekte auf neue Speicherorte zeigen.

Deep Copy in C++

Kopierkonstruktor vs. Zuweisungsoperator

Der Hauptunterschied zwischen dem Kopierkonstruktor und dem Zuweisungsoperator besteht darin, dass der Kopierkonstruktor bei jedem Aufruf einen neuen Speicher erstellt, während der Zuweisungsoperator keinen neuen Speicher erstellt.

Welche der folgenden beiden Anweisungen ruft den Kopierkonstruktor und welche den Zuweisungsoperator auf?

MyClass t1, t2; MyClass t3 = t1; // ---->(1) t2 = t1; // -----> (2)>

Ein Kopierkonstruktor wird aufgerufen, wenn ein neues Objekt aus einem vorhandenen Objekt als Kopie des vorhandenen Objekts erstellt wird. Der Zuweisungsoperator wird aufgerufen, wenn einem bereits initialisierten Objekt ein neuer Wert von einem anderen vorhandenen Objekt zugewiesen wird. Im obigen Beispiel ruft (1) den Kopierkonstruktor und (2) den Zuweisungsoperator auf. Weitere Einzelheiten finden Sie hier.

Beispiel – Klasse, für die ein Kopierkonstruktor erforderlich ist

Im Folgenden finden Sie ein vollständiges C++-Programm, das die Verwendung des Copy-Konstruktors demonstriert. In der folgenden String-Klasse müssen wir einen Kopierkonstruktor schreiben.

Beispiel:

C++




// C++ program to demonstrate the> // Working of Copy constructor> #include> #include> using> namespace> std;> class> String {> private>:> >char>* s;> >int> size;> public>:> >String(>const> char>* str = NULL);>// constructor> >~String() {>delete>[] s; }>// destructor> >String(>const> String&);>// copy constructor> >void> print()> >{> >cout << s << endl;> >}>// Function to print string> >void> change(>const> char>*);>// Function to change> };> // In this the pointer returns the CHAR ARRAY> // in the same sequence of string object but> // with an additional null pointer ' '> String::String(>const> char>* str)> {> >size =>strlen>(str);> >s =>new> char>[size + 1];> >strcpy>(s, str);> }> void> String::change(>const> char>* str)> {> >delete>[] s;> >size =>strlen>(str);> >s =>new> char>[size + 1];> >strcpy>(s, str);> }> String::String(>const> String& old_str)> {> >size = old_str.size;> >s =>new> char>[size + 1];> >strcpy>(s, old_str.s);> }> int> main()> {> >String str1(>'GeeksQuiz'>);> >String str2 = str1;> >str1.print();>// what is printed ?> >str2.print();> >str2.change(>'techcodeview.com'>);> >str1.print();>// what is printed now ?> >str2.print();> >return> 0;> }>

>

>

Ausgabe

GeeksQuiz GeeksQuiz GeeksQuiz techcodeview.com>

Was wäre das Problem, wenn wir den Kopierkonstruktor aus dem obigen Code entfernen würden?

Wenn wir den Kopierkonstruktor aus dem obigen Programm entfernen, erhalten wir nicht die erwartete Ausgabe. Die an str2 vorgenommenen Änderungen wirken sich auch auf str1 aus, was niemals erwartet wird.

C++




#include> #include> using> namespace> std;> class> String {> private>:> >char>* s;> >int> size;> public>:> >String(>const> char>* str = NULL);>// constructor> >~String() {>delete>[] s; }>// destructor> >void> print() { cout << s << endl; }> >void> change(>const> char>*);>// Function to change> };> String::String(>const> char>* str)> {> >size =>strlen>(str);> >s =>new> char>[size + 1];> >strcpy>(s, str);> }> // In this the pointer returns the CHAR ARRAY> // in the same sequence of string object but> // with an additional null pointer ' '> void> String::change(>const> char>* str) {>strcpy>(s, str); }> int> main()> {> >String str1(>'GeeksQuiz'>);> >String str2 = str1;> >str1.print();>// what is printed ?> >str2.print();> >str2.change(>'techcodeview.com'>);> >str1.print();>// what is printed now ?> >str2.print();> >return> 0;> }>

>

Verzeichnisnamen unter Linux ändern

>

Ausgabe:

GeeksQuiz GeeksQuiz techcodeview.com techcodeview.com>

Können wir den Kopierkonstruktor privat machen?

Ja, Ein Kopierkonstruktor kann privat gemacht werden. Wenn wir einen Kopierkonstruktor in einer Klasse privat machen, werden Objekte dieser Klasse nicht kopierbar. Dies ist besonders nützlich, wenn unsere Klasse über Zeiger oder dynamisch zugewiesene Ressourcen verfügt. In solchen Situationen können wir entweder unseren eigenen Kopierkonstruktor wie im obigen String-Beispiel schreiben oder einen privaten Kopierkonstruktor erstellen, damit Benutzer zur Laufzeit Compilerfehler statt Überraschungen erhalten.

Warum muss ein Argument an einen Kopierkonstruktor als Referenz übergeben werden?

Ein Kopierkonstruktor wird aufgerufen, wenn ein Objekt als Wert übergeben wird. Der Kopierkonstruktor selbst ist eine Funktion. Wenn wir also in einem Kopierkonstruktor ein Argument als Wert übergeben, erfolgt ein Aufruf des Kopierkonstruktors, der zu einer nicht terminierenden Aufrufkette führt. Daher lässt der Compiler nicht zu, dass Parameter als Wert übergeben werden.

Warum sollte das Argument für einen Kopierkonstruktor const sein?

Ein Grund zum Bestehen const Referenz ist, dass wir verwenden sollten const in C++, wo immer möglich, damit Objekte nicht versehentlich geändert werden. Dies ist ein guter Grund für die Übergabe der Referenz als const , aber es steckt mehr dahinter als „ Warum sollte das Argument für einen Kopierkonstruktor const sein?