Prérequis: Constructeur en C++
UN constructeur de copie est une fonction membre qui initialise un objet en utilisant un autre objet de la même classe. En termes simples, un constructeur qui crée un objet en l'initialisant avec un objet de la même classe, créé précédemment, est appelé un constructeur de copie .
Le constructeur de copie est utilisé pour initialiser les membres d'un objet nouvellement créé en copiant les membres d'un objet déjà existant.
Le constructeur de copie prend une référence à un objet de la même classe comme argument.
Sample(Sample &t) { id=t.id; }>
Le processus d'initialisation des membres d'un objet via un constructeur de copie est appelé initialisation de copie.
Elle est également appelée initialisation par membre, car le constructeur de copie initialise un objet avec l'objet existant, tous deux appartenant à la même classe, membre par membre.
Le constructeur de copie peut être défini explicitement par le programmeur. Si le programmeur ne définit pas le constructeur de copie, le compilateur le fait pour nous.
Exemple:
supprimer le fichier en java

Syntaxe du constructeur de copie
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;> }> |
>
>Sortir
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;> }> |
>
>Sortir
1001 Manjeet 10000 1001 Manjeet>
Caractéristiques du constructeur de copie
1. Le constructeur de copie est utilisé pour initialiser les membres d'un objet nouvellement créé en copiant les membres d'un objet déjà existant.
2. Le constructeur de copie prend une référence à un objet de la même classe comme argument. Si vous transmettez l'objet par valeur dans le constructeur de copie, cela entraînera un appel récursif au constructeur de copie lui-même. Cela se produit parce que le passage par valeur implique de faire une copie, et faire une copie implique d'appeler le constructeur de copie, conduisant à une boucle infinie. L'utilisation d'une référence évite cette récursion. Nous utilisons donc la référence d'objets pour éviter les appels infinis.
Sample(Sample &t) { id=t.id; }>
3. Le processus d'initialisation des membres d'un objet via un constructeur de copie est connu sous le nom de copie de l'initialisation.
4 . Elle est également appelée initialisation par membre car le constructeur de copie initialise un objet avec l'objet existant, tous deux appartenant à la même classe sur une base de copie membre par membre.
5. Le constructeur de copie peut être défini explicitement par le programmeur. Si le programmeur ne définit pas le constructeur de copie, le compilateur le fait pour nous.
Exemple:
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;> }> |
>
>Sortir
p1.x = 10, p1.y = 15 p2.x = 10, p2.y = 15>
Types de constructeurs de copie
1. Constructeur de copie par défaut
Un constructeur de copie défini implicitement copiera les bases et les membres d'un objet dans le même ordre qu'un constructeur initialiserait les bases et les membres de l'objet.
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;> }> |
>
>Sortir
ID=10 ID=10>
2. Constructeur de copie défini par l'utilisateur
Un constructeur de copie défini par l'utilisateur est généralement nécessaire lorsqu'un objet possède des pointeurs ou des références non partageables, comme vers un fichier, auquel cas un destructeur et un opérateur d'affectation doivent également être écrits.
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;> }> |
décompression sous Linux
>
>Sortir
ID=10 ID=10>
C++
algorithme minimax
// 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;> }> |
>
>Sortir
1001 Ram 10000 1001 Ram 10000>
Quand le constructeur de copie est-il appelé ?
En C++, un constructeur de copie peut être appelé dans les cas suivants :
- Lorsqu'un objet de la classe est renvoyé par valeur.
- Lorsqu'un objet de la classe est passé (à une fonction) par valeur en argument.
- Lorsqu'un objet est construit à partir d'un autre objet de la même classe.
- Lorsque le compilateur génère un objet temporaire.
Il n'est cependant pas garanti qu'un constructeur de copie sera appelé dans tous ces cas, car le standard C++ permet au compilateur d'optimiser la copie dans certains cas, un exemple est le optimisation de la valeur de retour (parfois appelé RVO).
Copier Elision
Dans l'élision de copie, le compilateur empêche la création de copies supplémentaires, ce qui permet d'économiser de l'espace et d'améliorer la complexité du programme (à la fois en temps et en espace) ; Rendant ainsi le code plus optimisé.
Exemple:
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;> }> |
>
>Sortir
GFG! GFG! GFG!>
Maintenant, c'est au compilateur de décider ce qu'il veut imprimer, il peut soit imprimer la sortie ci-dessus, soit imprimer le cas 1 ou le cas 2 ci-dessous, et c'est ce que Optimisation de la valeur de retour est. En mots simples, OVR est une technique qui donne au compilateur un pouvoir supplémentaire pour terminer l'objet temporaire créé, ce qui entraîne une modification du comportement/des caractéristiques observables du programme final.
Cas 1:
GFG! GFG!>
Cas 2 :
GFG!>
Quand un constructeur de copie défini par l’utilisateur est-il nécessaire ?
Si nous ne définissons pas notre propre constructeur de copie, le compilateur C++ crée un constructeur de copie par défaut pour chaque classe qui effectue une copie par membre entre les objets. Le constructeur de copie créé par le compilateur fonctionne bien en général. Nous devons définir notre propre constructeur de copie uniquement si un objet a des pointeurs ou une allocation d'exécution de la ressource comme un descripteur de fichier , une connexion réseau, etc.
Le défaut le constructeur ne fait qu'une copie superficielle.
La copie approfondie n'est possible qu'avec un constructeur de copie défini par l'utilisateur. Dans un constructeur de copie défini par l'utilisateur, nous nous assurons que les pointeurs (ou références) des objets copiés pointent vers de nouveaux emplacements mémoire.
Constructeur de copie vs opérateur d'affectation
La principale différence entre le constructeur de copie et l'opérateur d'affectation est que le constructeur de copie crée un nouveau stockage en mémoire à chaque fois qu'il est appelé, tandis que l'opérateur d'affectation ne crée pas de nouveau stockage en mémoire.
Laquelle des deux instructions suivantes appelle le constructeur de copie et laquelle appelle l'opérateur d'affectation ?
np.linspace
MyClass t1, t2; MyClass t3 = t1; // ---->(1) t2 = t1 ; // -----> (2)>
Un constructeur de copie est appelé lorsqu'un nouvel objet est créé à partir d'un objet existant, en tant que copie de l'objet existant. L'opérateur d'affectation est appelé lorsqu'un objet déjà initialisé se voit attribuer une nouvelle valeur à partir d'un autre objet existant. Dans l'exemple ci-dessus (1) appelle le constructeur de copie et (2) appelle l'opérateur d'affectation. Voir ceci pour plus de détails.
Exemple – Classe où un constructeur de copie est requis
Voici un programme C++ complet pour démontrer l’utilisation du constructeur Copy. Dans la classe String suivante, nous devons écrire un constructeur de copie.
Exemple:
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;> }> |
>
>Sortir
GeeksQuiz GeeksQuiz GeeksQuiz techcodeview.com>
Quel serait le problème si nous supprimions le constructeur de copie du code ci-dessus ?
Si nous supprimons le constructeur de copie du programme ci-dessus, nous n'obtenons pas le résultat attendu. Les modifications apportées à str2 se reflètent également dans str1, ce qui n'est jamais prévu.
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;> }> |
>
>
Sortir:
GeeksQuiz GeeksQuiz techcodeview.com techcodeview.com>
Pouvons-nous rendre le constructeur de copie privé ?
Oui, un constructeur de copie peut être rendu privé. Lorsque nous rendons un constructeur de copie privé dans une classe, les objets de cette classe deviennent non copiables. Ceci est particulièrement utile lorsque notre classe dispose de pointeurs ou de ressources allouées dynamiquement. Dans de telles situations, nous pouvons soit écrire notre propre constructeur de copie comme l'exemple de chaîne ci-dessus, soit créer un constructeur de copie privée afin que les utilisateurs obtiennent des erreurs de compilation plutôt que des surprises au moment de l'exécution.
Pourquoi l'argument d'un constructeur de copie doit-il être passé comme référence ?
Un constructeur de copie est appelé lorsqu'un objet est passé par valeur. Le constructeur de copie lui-même est une fonction. Ainsi, si nous passons un argument par valeur dans un constructeur de copie, un appel au constructeur de copie serait effectué pour appeler le constructeur de copie qui devient une chaîne d'appels sans fin. Par conséquent, le compilateur ne permet pas de transmettre les paramètres par valeur.
Pourquoi l'argument d'un constructeur de copie devrait être const ?
Une raison pour réussir const la référence est que nous devrions utiliser const en C++ autant que possible afin que les objets ne soient pas modifiés accidentellement. C'est une bonne raison pour passer la référence comme const , mais il y a plus que « Pourquoi l’argument d’un constructeur de copie devrait-il être const ? »