Tema
22
Constructores
y Destructores
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Teoría:
Necesidad
de escribir un constructor de copia
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ha
llegado ya el momento de explicar cómo surge la necesidad
de escribir un constructor de copia distinto del que
proporciona el compilador. Considérese una clase Alumno
con dos variablesmiembro: un puntero a char llamado
nombre y un long llamado nmat
que representa el número de matrícula..
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class
Alumno {
char* nombre;
long nmat;
...
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
En
realidad, esta clase no incluye el nombre del alumno, sino sólo
un puntero a carácter que permitirá almacenar la dirección
de memoria donde está realmente almacenado el nombre. Esta
memoria se reservará dinámicamente cuando el objeto
vaya a ser inicializado. Lo importante es darse cuenta de que el
nombre no es realmente una variable miembro de la clase: la variable
miembro es un puntero a la zona de memoria donde está almacenado.
Esta situación se puede ver gráficamente en la figura
1, en la que se muestra un objeto a de la clase Alumno.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Supóngase
ahora que con el constructor de copia suministrado
por el compilador se crea un nuevo objeto b a partir
de a. Las variables miembro de b van
a ser una copia bit a bit de las del objeto a. Esto
quiere decir que la variable miembro b.nombre contiene
la misma dirección de memoria que a.nombre.
Esta situación se representa gráficamente en la figura
2: ambos objetos apuntan a la misma dirección de memoria.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
La
situación mostrada en la figura 2 puede tener consecuencias
no deseadas. Por ejemplo, si se quiere cambiar el nombre del Alumno
a, lo primero que se hace es liberar la memoria a la que
apunta a.nombre, reservar memoria para el nuevo nombre
haciendo que a.nombre apunte al comienzo de dicha memoria, y almacenar
allí el nuevo nombre de a. Como el objeto
b no se ha tocado, su variable miembro b.nombre
se ha quedado apuntado a una posición de memoria que ha sido
liberada en el proceso de cambio de nombre de a. La
consecuencia es que b ha perdido información
y los más probable es que el programa falle.
Se
llega a una situación parecida cuando se destruye uno de
los dos objetos a o b. Al destruir uno de los objetos
se libera la memoria que comparten, con el consiguiente perjuicio
para el objeto que queda, puesto que su puntero contiene la dirección
de una zona de memoria liberada, disponible para almacenar otra
información.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Finalmente,
la figura 3 muestra la situación a la que se llega con un
constructor de copia correctamente programado por
el usuario. En este caso, el constructor no copia bit a bit
la dirección contenida en a.nombre, sino que
reserva memoria, copia a esa memoria el contenido apuntado por a.nombre,
y guarda en b.nombre la dirección de esa nueva
memoria reservada. Ninguno de los problemas anteriores sucede ahora.
|
|
|
|
|
|
|
|
|
|
|
|
|
|