Ver Mensaje Individual
  #5 (permalink)  
Antiguo 12/04/2015, 14:58
eferion
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 7 meses
Puntos: 204
Respuesta: Tengo una duda con los punteros en los atributos

Cita:
Iniciado por Cardo2095 Ver Mensaje
- me quedo una duda con el constructor que me dijiste xq no me da el error que dijiste sino que el IDE si lo asignaba como bueno, usa visual c++ 2010
Que un compilador concreto sepa sortear tu error no quiere decir que lo estés haciendo bien... puede que simplemente sean casualidades de la vida y eso no evita que en el futuro o bajo otras condiciones el programa empiece a fallar.

Cita:
Iniciado por Cardo2095 Ver Mensaje
-y además me preguntaba si a la hora de crear un objeto, por ejemplo:
quiero crear perro pero nose si debo crear tambien el objeto animal y asignarselo a perro o que.
Si tu tienes una clase "Perro", que hereda de otra "Animal" y tu quieres crear una instancia de "Perro", únicamente tienes que preocuparte de crear un "Perro".

Cuando una clase hereda de otra los constructores de la clase hija, por defecto, van a llamar al constructor por defecto de la clase padre. Si necesitas que un constructor de la clase hija llame a un constructor concreto de la clase padre tienes que indicarlo explícitamente:

Código C++:
Ver original
  1. class Animal
  2. {
  3.   public:
  4.     Animal( )
  5.     { std::cout << "Animal( )" << std::endl; }
  6.  
  7.     Animal( const Animal& )
  8.     { std::cout << "Animal( Animal )" << std::endl; }
  9. };
  10.  
  11. class Perro : public Animal
  12. {
  13.   public:
  14.  
  15.     // Este constructor llamará al constructor por defecto de "Animal"
  16.     Perro( )
  17.    { std::cout << "Perro()" << std::endl; }
  18.  
  19.     // Fíjate que aquí llamamos al constructor copia de "Animal"
  20.     Perro( const Perro& perro ) : Animal( perro )
  21.     { std::cout << "Perro( Perro )" << std::endl; }
  22. };
  23.  
  24. int main( )
  25. {
  26.   std::cout << "------" << std::endl;
  27.   Perro perro;
  28.   std::cout << "------" << std::endl;
  29.   Perro perro2( perro );
  30.   std::cout << "------" << std::endl;
  31. }

Pero claro, estas llamadas entre constructores solo tiene que tenerlas en cuenta el que programa los constructores. Es algo totalmente transparente para el que usa las clases.

Cita:
Iniciado por Cardo2095 Ver Mensaje
lo que tengo que hacer es una lista y crear muchos perros, pero nose si debo crear una lista para animal o solo la del perro, debido a que nose si a la hora de asignar los atributos a perro solo se crea perro o si tambien debo crear animal.
Cuando tu tienes una clase base y una o varias hijas, puedes hacer algo tal que:

Código C++:
Ver original
  1. // aunque la variable "animal" es de tipo "Animal", realmente almacena un perro
  2. // Esto es lo que se llama polimorfismo
  3. Animal* animal = new Perro;
  4.  
  5. // Esta línea dará error porque "Animal" no hereda de "Perro"
  6. Perro* perro = new Animal;

Lo que sucede es que el polimorfismo es una característica de nivel medio en C++, tiene sus riesgos y es mejor controlar primero la base antes de lanzarse a este tipo de prácticas.

Si aun así decides usar polimorfismo, te recomiendo usar siempre punteros, si no vas a perder información:

Código C++:
Ver original
  1. class Animal
  2. {
  3.   public:
  4.     Animal( )
  5.     { std::cout << "Animal( )" << std::endl; }
  6.  
  7.     Animal( const Animal& )
  8.    { std::cout << "Animal( Animal )" << std::endl; }
  9. };
  10.  
  11. class Perro : public Animal
  12. {
  13.   public:
  14.  
  15.     Perro( )
  16.    { std::cout << "Perro()" << std::endl; }
  17.  
  18.     Perro( const Perro& perro ) : Animal( perro )
  19.     { std::cout << "Perro( Perro )" << std::endl; }
  20. };
  21.  
  22. int main( )
  23. {
  24.   std::cout << "------" << std::endl;
  25.   Perro perro;
  26.   std::cout << "------" << std::endl;
  27.   // Fíjate que aquí no se llama al constructor de perro
  28.   // Lo que acaba de suceder es que has creado un "Animal" a partir de un "Perro"
  29.   // pero no has creado un nuevo "Perro"
  30.   Animal animal( perro );
  31.   std::cout << "------" << std::endl;
  32. }

Luego, aparte de esto tienes que tener en cuenta la sobrecarga de operadores, los métodos virtuales, destructores virtuales y otra serie de conceptos que si no dominas bien te van a frustrar demasiado.

Cita:
Iniciado por vangodp Ver Mensaje
Código C++:
Ver original
  1. void setId ( int *id ) { this->id = id; } //se usa para apuntar a un id que relacionaremos al animal animal
No tiene demasiado sentido, en este caso, que id sea un puntero... como ejemplo para demostrar que se puede, vale. Pero mejor no complicarse... cuando un elemento necesite ser un puntero tranquilo que te darás cuenta porque no podrás hacer las cosas usando variables "por valor".

Cita:
Iniciado por vangodp Ver Mensaje
Código C++:
Ver original
  1. unPerro.setId ( &id ); //hacemos que perro apunte el id... No hay sentido ya que el propio Animal deberia albergar el ID, pero es solo un ejemplo de como debe hacer con punteros.
Y aquí está el peligro de usar punteros y referencias... ¿qué sucede si "id" es una variable local? Cuando salgamos de la función la variable se perderá y el puntero se quedará apuntando a algo que ya no existe. Aquí esto no sucede porque es la variable, aunque local, está en el main, pero me sirve para ilustrar el ejemplo.

Cita:
Iniciado por vangodp Ver Mensaje
Código C++:
Ver original
  1. Perro *ptrPerro = new Perro[10];
  2.     // Se verifica que exista el apunte a algo
  3.     if ( !ptrPerro ){ std::cout << "Error en la asignacion" << std::endl; return 1; }
Si falla el new se va a lanzar una excepción... tu código solo va a funcionar como pretendes si modificas la línea del new tal que:

Código C++:
Ver original
  1. Perro *ptrPerro = new (std::nothrow) Perro[10];

Pero sin ese "nothrow" el new va a lanzar excepciones.