logo

Copiați constructorul în C++

Condiție prealabilă: Constructor în C++

A constructor de copiere este o funcție membru care inițializează un obiect folosind un alt obiect din aceeași clasă. În termeni simpli, un constructor care creează un obiect prin inițializarea acestuia cu un obiect din aceeași clasă, care a fost creat anterior este cunoscut ca un constructor de copiere .

Constructorul de copiere este folosit pentru a inițializa membrii unui obiect nou creat prin copierea membrilor unui obiect deja existent.



Constructorul de copiere preia o referință la un obiect din aceeași clasă ca un argument.

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

Procesul de inițializare a membrilor unui obiect printr-un constructor de copiere este cunoscut sub numele de inițializare de copiere.

Se mai numește inițializare la nivel de membru deoarece constructorul de copiere inițializează un obiect cu obiectul existent, ambele aparținând aceleiași clase pe bază de copiere membru cu membru.

Constructorul de copiere poate fi definit explicit de către programator. Dacă programatorul nu definește constructorul de copiere, compilatorul o face pentru noi.

Exemplu:

comenzi rapide linux
Sintaxa de Copy Constructor cu Exemplu

Sintaxa lui Copy Constructor

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;> }>

>

>

Ieșire

 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;> }>

>

>

Ieșire

 1001 Manjeet 10000 1001 Manjeet>

Caracteristicile Copy Constructor

1. Constructorul de copiere este folosit pentru a inițializa membrii unui obiect nou creat prin copierea membrilor unui obiect deja existent.

2. Constructorul de copiere preia o referință la un obiect din aceeași clasă ca un argument. Dacă treceți obiectul după valoare în constructorul de copiere, ar avea ca rezultat un apel recursiv către constructorul de copiere însuși. Acest lucru se întâmplă deoarece trecerea după valoare implică realizarea unei copii, iar realizarea unei copii implică apelarea constructorului de copiere, ceea ce duce la o buclă infinită. Utilizarea unei referințe evită această recursivitate. Deci folosim referința la obiecte pentru a evita apelurile infinite.

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

3. Procesul de inițializare a membrilor unui obiect printr-un constructor de copiere este cunoscut ca inițializarea copiei.

4 . Se mai numește și inițializare în funcție de membru deoarece constructorul de copiere inițializează un obiect cu obiectul existent, ambele aparținând aceleiași clase pe o bază de copiere membru cu membru.

5. Constructorul de copiere poate fi definit explicit de către programator. Dacă programatorul nu definește constructorul de copiere, compilatorul o face pentru noi.

Exemplu:

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;> }>

>

>

Ieșire

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

Tipuri de constructori de copiere

1. Constructor de copiere implicit

Un constructor de copiere definit implicit va copia bazele și membrii unui obiect în aceeași ordine în care un constructor ar inițializa bazele și membrii obiectului.

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;> }>

>

>

Madhubala
Ieșire

 ID=10 ID=10>

2. Constructor de copiere definit de utilizator

Un constructor de copiere definit de utilizator este, în general, necesar atunci când un obiect deține pointeri sau referințe care nu pot fi partajate, cum ar fi un fișier, caz în care un destructor și un operator de atribuire ar trebui să fie, de asemenea, scrise.

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;> }>

>

>

Ieșire

 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;> }>

>

>

Ieșire

 1001 Ram 10000 1001 Ram 10000>

Când este numit constructorul de copiere?

În C++, un constructor de copiere poate fi apelat în următoarele cazuri:

  • Când un obiect al clasei este returnat prin valoare.
  • Când un obiect al clasei este transmis (la o funcție) prin valoare ca argument.
  • Când un obiect este construit pe baza unui alt obiect din aceeași clasă.
  • Când compilatorul generează un obiect temporar.

Cu toate acestea, nu este garantat că un constructor de copiere va fi apelat în toate aceste cazuri, deoarece standardul C++ permite compilatorului să optimizeze copia în anumite cazuri, un exemplu este optimizarea valorii returnate (uneori denumit RVO).

Copiați Elision

În copie elision, compilatorul împiedică realizarea de copii suplimentare, ceea ce are ca rezultat economisirea de spațiu și o îmbunătățire a complexității programului (atât timp cât și spațiu); Prin urmare, codul este mai optimizat.

Exemplu:

C++


arraylist sortată



// 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;> }>

>

>

Ieșire

 GFG! GFG! GFG!>

Acum este pe compilator să decidă ce dorește să imprime, ar putea fie să imprime rezultatul de mai sus, fie ar putea imprima cazul 1 sau cazul 2 de mai jos și asta este ceea ce Optimizarea valorii returnate este. Cu cuvinte simple, RVO este o tehnică care oferă compilatorului o putere suplimentară de a termina obiectul temporar creat, ceea ce are ca rezultat modificarea comportamentului/caracteristicilor observabile ale programului final.

Cazul 1:

GFG! GFG!>

Cazul 2:

GFG!>

Când este necesar un constructor de copiere definit de utilizator?

Dacă nu definim propriul constructor de copiere, compilatorul C++ creează un constructor de copiere implicit pentru fiecare clasă, care face o copie în funcție de membri între obiecte. Constructorul de copiere creat de compilator funcționează bine în general. Trebuie să ne definim propriul constructor de copiere numai dacă un obiect are pointeri sau orice alocare de execuție a resursei un mâner de fișier , o conexiune la rețea etc.

Implicit constructorul face doar o copie superficială.

copie superficială în C++

Copierea profundă este posibilă numai cu un constructor de copiere definit de utilizator. Într-un constructor de copiere definit de utilizator, ne asigurăm că pointerii (sau referințele) obiectelor copiate indică către noi locații de memorie.

Deep Copy în C++

Constructor de copiere vs Operator de atribuire

Principala diferență dintre Copy Constructor și Assignment Operator este că constructorul Copy realizează o nouă memorie de stocare de fiecare dată când este apelată, în timp ce operatorul de atribuire nu realizează o nouă memorie de stocare.

Care dintre următoarele două instrucțiuni apelează constructorul de copiere și care apelează operatorul de atribuire?

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

Un constructor de copiere este apelat atunci când un obiect nou este creat dintr-un obiect existent, ca o copie a obiectului existent. Operatorul de atribuire este apelat atunci când unui obiect deja inițializat i se atribuie o nouă valoare de la un alt obiect existent. În exemplul de mai sus (1) apelează constructorul de copiere și (2) apelează operatorul de atribuire. Vezi asta pentru mai multe detalii.

Exemplu – Clasa unde este necesar un constructor de copiere

Mai jos este un program complet C++ pentru a demonstra utilizarea constructorului Copy. În următoarea clasă String, trebuie să scriem un constructor de copiere.

Exemplu:

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;> }>

>

Ieșire

GeeksQuiz GeeksQuiz GeeksQuiz techcodeview.com>

Care ar fi problema dacă eliminăm constructorul de copiere din codul de mai sus?

Dacă eliminăm constructorul de copiere din programul de mai sus, nu obținem rezultatul așteptat. Modificările aduse str2 se reflectă și în str1, ceea ce nu este de așteptat niciodată.

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;> }>

>

>

excepție personalizată în java

Ieșire:

GeeksQuiz GeeksQuiz techcodeview.com techcodeview.com>

Putem face constructorul de copiere privat?

Da, un constructor de copiere poate fi făcut privat. Când facem privat un constructor de copiere într-o clasă, obiectele acelei clase devin necopiabile. Acest lucru este util în special atunci când clasa noastră are pointeri sau resurse alocate dinamic. În astfel de situații, putem fie să scriem propriul constructor de copiere, ca exemplul String de mai sus, fie să facem un constructor de copiere privată, astfel încât utilizatorii să obțină erori de compilator mai degrabă decât surprize în timpul execuției.

De ce argumentul unui constructor de copiere trebuie transmis ca referință?

Un constructor de copiere este apelat atunci când un obiect este transmis după valoare. Constructorul de copiere în sine este o funcție. Deci, dacă trecem un argument după valoare într-un constructor de copiere, ar fi făcut un apel către constructorul de copiere pentru a apela constructorul de copiere care devine un lanț de apeluri neterminând. Prin urmare, compilatorul nu permite trecerea parametrilor după valoare.

De ce argumentul unui constructor de copiere ar trebui să fie const?

Un motiv pentru trecere const referința este că ar trebui să folosim const în C++ ori de câte ori este posibil, astfel încât obiectele să nu fie modificate accidental. Acesta este un motiv bun pentru a trece referința ca const , dar este mai mult decât „ De ce argumentul către un constructor de copiere ar trebui să fie const?’