Prerequisito: Costruttore in C++
UN copia costruttore è una funzione membro che inizializza un oggetto utilizzando un altro oggetto della stessa classe. In termini semplici, un costruttore che crea un oggetto inizializzandolo con un oggetto della stessa classe, creato in precedenza, è noto come copia costruttore .
Il costruttore di copie viene utilizzato per inizializzare i membri di un oggetto appena creato copiando i membri di un oggetto già esistente.
Il costruttore di copie accetta un riferimento a un oggetto della stessa classe come argomento.
Sample(Sample &t) { id=t.id; }>
Il processo di inizializzazione dei membri di un oggetto tramite un costruttore di copie è noto come inizializzazione della copia.
È detta anche inizializzazione membro perché il costruttore della copia inizializza un oggetto con l'oggetto esistente, entrambi appartenenti alla stessa classe in base alla copia membro per membro.
Il costruttore della copia può essere definito esplicitamente dal programmatore. Se il programmatore non definisce il costruttore della copia, il compilatore lo fa per noi.
Esempio:
sito web come coomeet

Sintassi del costruttore di copia
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;> }> |
>
>Produzione
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;> }> |
>
>Produzione
1001 Manjeet 10000 1001 Manjeet>
Caratteristiche del costruttore di copie
1. Il costruttore di copia viene utilizzato per inizializzare i membri di un oggetto appena creato copiando i membri di un oggetto già esistente.
2. Il costruttore di copie accetta un riferimento a un oggetto della stessa classe come argomento. Se si passa l'oggetto per valore nel costruttore di copie, si otterrebbe una chiamata ricorsiva al costruttore di copie stesso. Ciò accade perché il passaggio per valore implica la creazione di una copia, e la creazione di una copia implica la chiamata al costruttore della copia, portando a un ciclo infinito. L'utilizzo di un riferimento evita questa ricorsione. Quindi usiamo il riferimento agli oggetti per evitare chiamate infinite.
Sample(Sample &t) { id=t.id; }>
3. Il processo di inizializzazione dei membri di un oggetto tramite un costruttore di copie è noto come inizializzazione della copia.
4 . È detta anche inizializzazione membro perché il costruttore della copia inizializza un oggetto con l'oggetto esistente, entrambi appartenenti alla stessa classe su una base di copia membro per membro.
5. Il costruttore della copia può essere definito esplicitamente dal programmatore. Se il programmatore non definisce il costruttore della copia, il compilatore lo fa per noi.
Esempio:
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;> }> |
>
>Produzione
p1.x = 10, p1.y = 15 p2.x = 10, p2.y = 15>
Tipi di costruttori di copia
1. Costruttore di copia predefinito
Un costruttore di copie definito implicitamente copierà le basi e i membri di un oggetto nello stesso ordine in cui un costruttore inizializzerebbe le basi e i membri dell'oggetto.
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;> }> |
>
>Produzione
ID=10 ID=10>
2. Costruttore di copia definito dall'utente
Un costruttore di copie definito dall'utente è generalmente necessario quando un oggetto possiede puntatori o riferimenti non condivisibili, come a un file, nel qual caso dovrebbero essere scritti anche un distruttore e un operatore di assegnazione
programma Python per la ricerca binaria
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;> }> |
>
>Produzione
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;> }> |
>
>Produzione
1001 Ram 10000 1001 Ram 10000>
Quando viene chiamato il costruttore della copia?
In C++, un costruttore di copia può essere chiamato nei seguenti casi:
- Quando un oggetto della classe viene restituito per valore.
- Quando un oggetto della classe viene passato (a una funzione) in base al valore come argomento.
- Quando un oggetto viene costruito in base a un altro oggetto della stessa classe.
- Quando il compilatore genera un oggetto temporaneo.
Non è tuttavia garantito che in tutti questi casi venga chiamato un costruttore di copia, poiché lo standard C++ consente al compilatore di ottimizzare la copia in determinati casi, un esempio è ottimizzazione del valore di ritorno (a volte indicato come RVO).
Copia Elisione
Nell'elisione delle copie, il compilatore impedisce la creazione di copie extra, il che si traduce in un risparmio di spazio e una migliore complessità del programma (sia in termini di tempo che di spazio); Quindi rendendo il codice più ottimizzato.
Esempio:
C++
.tostring java
// 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;> }> |
>
>Produzione
GFG! GFG! GFG!>
Ora spetta al compilatore decidere cosa vuole stampare, potrebbe stampare l'output sopra oppure stampare il caso 1 o il caso 2 di seguito, e questo è ciò che Ottimizzazione del valore di ritorno È. In parole semplici, RVO è una tecnica che conferisce al compilatore un potere aggiuntivo per terminare l'oggetto temporaneo creato, il che si traduce nella modifica del comportamento/caratteristiche osservabili del programma finale.
Caso 1:
GFG! GFG!>
Caso 2:
GFG!>
Quando è necessario un costruttore di copie definito dall'utente?
Se non definiamo il nostro costruttore di copia, il compilatore C++ crea un costruttore di copia predefinito per ogni classe che esegue una copia a livello di membro tra oggetti. Il costruttore di copie creato dal compilatore funziona bene in generale. Dobbiamo definire il nostro costruttore di copie solo se un oggetto ha puntatori o qualsiasi allocazione di runtime della risorsa come un handle di file , una connessione di rete, ecc.
Il predefinito il costruttore esegue solo copie superficiali.
La copia approfondita è possibile solo con un costruttore di copia definito dall'utente. In un costruttore di copie definito dall'utente, ci assicuriamo che i puntatori (o riferimenti) degli oggetti copiati puntino a nuove posizioni di memoria.
Costruttore di copia vs Operatore di assegnazione
La differenza principale tra il costruttore di copia e l'operatore di assegnazione è che il costruttore di copia crea una nuova archiviazione di memoria ogni volta che viene chiamato mentre l'operatore di assegnazione non crea una nuova archiviazione di memoria.
Quale delle seguenti due istruzioni chiama il costruttore di copia e quale chiama l'operatore di assegnazione?
MyClass t1, t2; MyClass t3 = t1; // ---->(1) t2 = t1; // -----> (2)>
Un costruttore di copie viene chiamato quando un nuovo oggetto viene creato da un oggetto esistente, come copia dell'oggetto esistente. L'operatore di assegnazione viene chiamato quando a un oggetto già inizializzato viene assegnato un nuovo valore da un altro oggetto esistente. Nell'esempio precedente (1) chiama il costruttore di copia e (2) chiama l'operatore di assegnazione. Vedi questo per maggiori dettagli.
Esempio: classe in cui è richiesto un costruttore di copia
Di seguito è riportato un programma C++ completo per dimostrare l'uso del costruttore Copy. Nella seguente classe String, dobbiamo scrivere un costruttore di copie.
Esempio:
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;> }> |
>
>Produzione
GeeksQuiz GeeksQuiz GeeksQuiz techcodeview.com>
Quale sarebbe il problema se rimuovessimo il costruttore di copia dal codice precedente?
Se rimuoviamo il costruttore di copia dal programma precedente, non otteniamo l'output previsto. Le modifiche apportate a str2 si riflettono anche in str1, cosa mai prevista.
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;> }> |
>
>
Produzione:
GeeksQuiz GeeksQuiz techcodeview.com techcodeview.com>
Possiamo rendere privato il costruttore della copia?
SÌ, un costruttore di copie può essere reso privato. Quando rendiamo privato un costruttore di copie in una classe, gli oggetti di quella classe diventano non copiabili. Ciò è particolarmente utile quando la nostra classe ha puntatori o risorse allocate dinamicamente. In tali situazioni, possiamo scrivere il nostro costruttore di copia come nell'esempio String precedente o creare un costruttore di copia privata in modo che gli utenti ricevano errori del compilatore anziché sorprese in fase di esecuzione.
funzione sottostringa Java
Perché l'argomento a un costruttore di copie deve essere passato come riferimento?
Un costruttore di copia viene chiamato quando un oggetto viene passato per valore. Il costruttore di copia stesso è una funzione. Quindi, se passiamo un argomento per valore in un costruttore di copie, verrebbe effettuata una chiamata al costruttore di copie per chiamare il costruttore di copie che diventa una catena di chiamate senza terminazione. Pertanto il compilatore non consente il passaggio dei parametri per valore.
Perché l'argomento per un costruttore di copie dovrebbe essere const?
Un motivo per passare cost il riferimento è che dovremmo usare cost in C++ ove possibile in modo che gli oggetti non vengano modificati accidentalmente. Questo è un buon motivo per passare il riferimento come cost , ma c'è di più oltre a ' Perché l’argomento per un costruttore di copie dovrebbe essere const?’