[C con Clase] Duda sobre ejemplo de la sección

Steven Davidson steven en conclase.net
Sab Ene 20 04:55:58 CET 2007


Hola Sorcerer,

El pasado 2007-01-19 23:11:44, Sorcerer escribió:

S> Hola a todos,
S> estoy leyendo esta parte del curso: http://c.conclase.net/curso/index.php?cap=037 
S> En el código de ejemplo para constructores virtuales, crean una función virtual llamada "clonar" para hacer copias de los objetos, diciendo que no se puede hacer directamente xq los constructores (en este caso, entiendo el constructor copia) no pueden ser virtuales.
S> Esto no me queda claro, como sería un ejemplo de lo que no se puede hacer ?

Veamos. Usaré las clase de ejemplo del curso. Supongamos que tenemos la siguiente función:

void func( Persona *ptr )
{
  // <¿tipo?> aux = *ptr;  // Podríamos intentar instanciar un objeto usando el constructor copia, pero no sabemos el tipo original de '*ptr'

  Persona *pAux = ptr.Clonar();  // Forma correcta
  ...
}

Digamos que necesitamos una copia del objeto pasado como parámetro. Lo que pasa es que no sabemos exactamente el tipo del objeto. Lo único que sabemos es que 'ptr' apunta a un objeto del tipo 'Persona' o sus descendientes. Por lo tanto, necesitamos algo parecido a un constructor virtual, pero esto no existe. Lo mejor que podemos hacer es usar la función miembro 'Clonar()'. Como no sabemos el tipo exacto, usamos el mecanismo de polimorfismo para que internamente escoja la versión correcta de 'Clonar()'. Por ejemplo, digamos que invocamos la función anterior de esta manera:

int main()
{
  Persona *pLista[10];
  ...
  pLista[0] = new Estudiante( "Pablo" );
  func( pLista[0] );  // Aquí pasamos un objeto 'Estudiante'
  ...
  pLista[1] = new Empleado( "Pepe" );
  func( pLista[1] );  // Aquí pasamos un objeto 'Empleado'
  ...
  pLista[2] = new Persona( "Paco" );
  func( pLista[2] );  // Aquí pasamos un objeto 'Persona'
  ...
}

Lo que tienes que observar es que al llegar a 'func()' no tenemos la menor idea del tipo original del parámetro. Si necesitamos crear un objeto basado en este parámetro, entonces no tenemos otra opción que usar la función miembro 'Clonar()'. Lo ideal sería usar un constructor copia virtual, donde el sistema polimórfico eligiera el constructo copia que precisemos. Sin embargo, esto no es posible de saberlo. Bueno, sí es posible, pero tendríamos que usar 'dynamic_cast' para determinar el tipo original para luego instanciar el objeto que nos interesa. Esto es,

void func2( Persona *ptr )
{
  if( dynamic_cast< Estudiante * >( ptr ) )
  {
    Estudiante aux;
    ...
  }
  else if( dynamic_cast< Empleado * >( ptr ) )
  {
    Empleado aux;
    ...
  }
  else
  {
    Persona aux;
    ...
  }
  ...
}

En general, esto no suele solucionar nuestros problemas o no es deseable. La opción que nos da una solución "elegante" es la de crear una función miembro que implemente algo parecido a un constructor virtual.

S> 

[CORTE]

S> Quité los constructores copia de las 2 clases derivadas a ver que pasaba, la respuesta que me da el programa es esta:
S> Emp: Carlos
S> Est: Jose
S> Per: constructor copia.
S> Emp: Carlos
S> Per: constructor copia.
S> Est: Jose
S> Pero no me queda claro que es lo que realiza... ¿como yo borré los constructores copia, se generaron otros por defecto?, xq en la respuesta se ve que se llaman los constructores copia de la class Persona, aunque yo no los llamé.

Exacto. Los constructores copia siempre existen, tanto si los implementas tú mismo como si no. El constructor copia de 'Persona' es invocado implícitamente al invocar a 'Clonar()' para cada elemento del array 'Gente'.


Espero haber aclarado las dudas.

Steven


Más información sobre la lista de distribución Cconclase