logo

Copiar constructor en C++

Requisito previo: Constructor en C++

A constructor de copias es una función miembro que inicializa un objeto usando otro objeto de la misma clase. En términos simples, un constructor que crea un objeto inicializándolo con un objeto de la misma clase, que ha sido creado previamente, se conoce como constructor de copias .



El constructor de copia se utiliza para inicializar los miembros de un objeto recién creado copiando los miembros de un objeto ya existente.

El constructor de copia toma una referencia a un objeto de la misma clase como argumento.

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

El proceso de inicializar miembros de un objeto a través de un constructor de copia se conoce como inicialización de copia.



También se denomina inicialización por miembros porque el constructor de copias inicializa un objeto con el objeto existente, ambos pertenecientes a la misma clase, miembro por copia.

El programador puede definir explícitamente el constructor de copia. Si el programador no define el constructor de la copia, el compilador lo hace por nosotros.

Ejemplo:



ordenar burbujas en java
Sintaxis de Copy Constructor con ejemplo

Sintaxis del constructor de copias

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

>

>

Producción

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

>

>

Producción

 1001 Manjeet 10000 1001 Manjeet>

Características del constructor de copias

1. El constructor de copia se utiliza para inicializar los miembros de un objeto recién creado copiando los miembros de un objeto ya existente.

2. El constructor de copia toma una referencia a un objeto de la misma clase como argumento. Si pasa el objeto por valor en el constructor de copia, resultaría en una llamada recursiva al constructor de copia. Esto sucede porque pasar por valor implica hacer una copia, y hacer una copia implica llamar al constructor de la copia, lo que genera un bucle infinito. El uso de una referencia evita esta recursividad. Entonces usamos referencia de Objetos para evitar llamadas infinitas.

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

3. El proceso de inicializar miembros de un objeto a través de un constructor de copia se conoce como inicialización de copia.

4 . También se denomina inicialización por miembros porque el constructor de copia inicializa un objeto con el objeto existente, ambos pertenecientes a la misma clase, copia miembro por miembro.

5. El programador puede definir explícitamente el constructor de copia. Si el programador no define el constructor de la copia, el compilador lo hace por nosotros.

Ejemplo:

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

>

>

Producción

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

Tipos de constructores de copias

1. Constructor de copia predeterminado

Un constructor de copia definido implícitamente copiará las bases y miembros de un objeto en el mismo orden en que un constructor inicializaría las bases y miembros del objeto.

C++


ubicación df



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

>

>

Producción

 ID=10 ID=10>

2. Constructor de copias definido por el usuario

Generalmente se necesita un constructor de copia definido por el usuario cuando un objeto posee punteros o referencias que no se pueden compartir, como a un archivo, en cuyo caso también se deben escribir un destructor y un operador de asignación.

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

>

>

Producción

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

>

>

Producción

 1001 Ram 10000 1001 Ram 10000>

¿Cuándo se llama al constructor de copias?

En C++, se puede llamar a un constructor de copia en los siguientes casos:

  • Cuando un objeto de la clase se devuelve por valor.
  • Cuando un objeto de la clase se pasa (a una función) por valor como argumento.
  • Cuando un objeto se construye en base a otro objeto de la misma clase.
  • Cuando el compilador genera un objeto temporal.

Sin embargo, no se garantiza que se llame a un constructor de copia en todos estos casos, porque el estándar C++ permite al compilador optimizar la copia en ciertos casos, un ejemplo es el optimización del valor de retorno (a veces denominado RVO).

agrupamiento

Copiar elisión

En la elisión de copia, el compilador evita la realización de copias adicionales, lo que ahorra espacio y mejora la complejidad del programa (tanto en tiempo como en espacio); Por lo tanto, el código está más optimizado.

Ejemplo:

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

>

>

Producción

 GFG! GFG! GFG!>

Ahora le corresponde al compilador decidir qué quiere imprimir, podría imprimir el resultado anterior o podría imprimir el caso 1 o el caso 2 a continuación, y esto es lo que Optimización del valor de retorno es. En palabras simples, RVO es una técnica que le da al compilador algún poder adicional para terminar el objeto temporal creado, lo que resulta en cambiar el comportamiento/características observables del programa final.

Caso 1:

GFG! GFG!>

Caso 2:

GFG!>

¿Cuándo se necesita un constructor de copias definido por el usuario?

Si no definimos nuestro propio constructor de copia, el compilador de C++ crea un constructor de copia predeterminado para cada clase que realiza una copia por miembros entre objetos. El constructor de copias creado por el compilador funciona bien en general. Necesitamos definir nuestro propio constructor de copia sólo si un objeto tiene punteros o cualquier asignación de tiempo de ejecución del recurso como un identificador de archivo , una conexión de red, etc.

El valor por defecto El constructor sólo hace una copia superficial.

copia superficial en C++

La copia profunda sólo es posible con un constructor de copias definido por el usuario. En un constructor de copias definido por el usuario, nos aseguramos de que los punteros (o referencias) de los objetos copiados apunten a nuevas ubicaciones de memoria.

Copia profunda en C++

Copiar constructor vs operador de asignación

La principal diferencia entre el constructor de copia y el operador de asignación es que el constructor de copia crea un nuevo almacenamiento de memoria cada vez que se llama, mientras que el operador de asignación no crea un nuevo almacenamiento de memoria.

¿Cuál de las dos declaraciones siguientes llama al constructor de copia y cuál llama al operador de asignación?

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

Se llama a un constructor de copia cuando se crea un nuevo objeto a partir de un objeto existente, como una copia del objeto existente. Se llama al operador de asignación cuando a un objeto ya inicializado se le asigna un nuevo valor de otro objeto existente. En el ejemplo anterior (1) llama al constructor de copia y (2) llama al operador de asignación. Vea esto para más detalles.

Ejemplo: clase donde se requiere un constructor de copia

A continuación se muestra un programa completo en C++ para demostrar el uso del constructor Copiar. En la siguiente clase String, debemos escribir un constructor de copia.

Ejemplo:

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

>

>

Producción

GeeksQuiz GeeksQuiz GeeksQuiz techcodeview.com>

¿Cuál sería el problema si eliminamos el constructor de copia del código anterior?

Si eliminamos el constructor de copias del programa anterior, no obtenemos el resultado esperado. Los cambios realizados en str2 también se reflejan en str1, lo que nunca se esperaba.

C++


Python convierte bytes a cadena



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

>

>

Producción:

GeeksQuiz GeeksQuiz techcodeview.com techcodeview.com>

¿Podemos hacer que el constructor de copias sea privado?

Sí, un constructor de copias se puede hacer privado. Cuando hacemos que un constructor de copias sea privado en una clase, los objetos de esa clase se vuelven no copiables. Esto es particularmente útil cuando nuestra clase tiene punteros o recursos asignados dinámicamente. En tales situaciones, podemos escribir nuestro propio constructor de copia como en el ejemplo de String anterior o crear un constructor de copia privado para que los usuarios obtengan errores de compilación en lugar de sorpresas en tiempo de ejecución.

¿Por qué se debe pasar como referencia un argumento a un constructor de copia?

Se llama a un constructor de copia cuando se pasa un objeto por valor. El constructor de copias en sí es una función. Entonces, si pasamos un argumento por valor en un constructor de copia, se realizará una llamada al constructor de copia para llamar al constructor de copia, lo que se convierte en una cadena de llamadas sin terminación. Por lo tanto, el compilador no permite pasar parámetros por valor.

¿Por qué el argumento de un constructor de copias debería ser constante?

Una razón para pasar constante referencia es que debemos usar constante en C++ siempre que sea posible para que los objetos no se modifiquen accidentalmente. Ésta es una buena razón para pasar la referencia como constante , pero hay más que ' ¿Por qué el argumento de un constructor de copias debería ser constante?