Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





C++ y POO

Iniciado por sukhur, 05 de Enero de 2007, 10:12:24 AM

« anterior - próximo »

sukhur

Hola, estaba inventándome un ejercicio para repasar una asignatura y me he encontrado con un problema. El ejercicio es más o menos:

Vehiculo
  matricula
  año
  precio
  motor
  getMatricula()
  getAño()
  getPrecio()
  getMotor()

Camion:Vehiculo
    pma
    longitud
    getPma()
    getLongitud()

Moto:Vehiculo
    cm3
    velpunta
    getCm3()
    getVelPunta()

Pues bien ahora yo quiero crear un vector :

Vehiculo *vecVehiculos[10];

vecVehiculos[0]=new Camion(,,,,);
vecVehiculos[1]=new Moto(,,,,);

pero que además pueda acceder a los métodos propios de cada subclase, por ejemplo:

vecVehiculos[0]->getPma();
vecVehiculos[1]->getCm3();

¿Con que se hace esto? ¿Polimorfismo? ¿Clases abstractas? ¿Dónde está Wally?

Fran

Lo puedes hacer de varias formas

1.Herencia + Casteo (si donde lo vayas a tratar sabes a q te estás refiriendo)

Es decir: Moto deriva de Vehiculo

Y si cuando vayas a tratar sabes q es una moto haciendo (Moto)(Vehiculos[2])->cm3

2. Implementación abstracta:

Hay un método virtual y/o abstracto (sin implementación o con devolucion de 0 o valor nulo) en vehiculo, que luego en moto por ejemplo lo implementas como heredado y sobreescrito como lo q te  haga falta de modo que cuando llames al metodo PMA de una moto por ejemplo te devuelva el de Vehiculo=0 y cuando llames al de camion (q lo habras implementado) te devuelva 40 Tn.

3. Y hay otra pero es una patata.

Estas son las q se me ocurren y para mi la mejor es la 2.

Diferencial

Hola sulhur,
Si no estoy equivocado que alguien me corrija se haria de la siguiente forma:


Vehiculo vec[10];
vec[0] = new Camion();
/*vec[0] contiene una instancia de camión y esto es posible a la herencia y al polimorfismo ya que has convertido un vehiculo a un camion.
Vehiculo tiene que ser una clase abstracta. No es necesario pero en tu caso no necesitas crearte objetos de tipo vehiculo ya que seran camion o moto.*/

//Ahora puedes acceder a los metodos de camion de esta forma
vec[0].getPMA();
//Lo mismo sucede con moto
vec[1] = new Moto();
vec[1].getCm3();

//El ejemplo que tu pones tambien es correcto usando punteros, aunque no se muy bien si te referias a lo que he puesto yo??
PARA TENER COSAS QUE NUNCA HAS TENIDO, TENDRÁS QUE HACER COSAS QUE NUNCA HAS HECHO.

sukhur

Entonces Fran, en Vehiculo tendria que poner ademas de las ya existentes estas otras:

virtual getPma()=0;
virtual getLongitud()=0;
virtual getCm3()=0;
virtual getVelPunta()=0;

Fran

Cita de: "sukhur"Entonces Fran, en Vehiculo tendria que poner ademas de las ya existentes estas otras:

virtual getPma()=0;
virtual getLongitud()=0;
virtual getCm3()=0;
virtual getVelPunta()=0;

Si. Yo adoptaría esa solución. Xq no recuerdo si en C++ se le podía poner abstract pero si lo declaras solo como abstract (q no tendrias mas que declararlas sin implementarlas), puede darte un error de abstract error code si las llamas desde un descendiente que no lo tenga implementado.

A lo mejor a alguien se le ocurre otra forma. Pero yo lo haría así

Fran

Cita de: "sukhur"Entonces Fran, en Vehiculo tendria que poner ademas de las ya existentes estas otras:

virtual getPma()=0;
virtual getLongitud()=0;
virtual getCm3()=0;
virtual getVelPunta()=0;

Si. Yo adoptaría esa solución. Xq no recuerdo si en C++ se le podía poner abstract (hace mas de 10 años q no lo toco) pero si lo declaras solo como abstract (q no tendrias mas que declararlas sin implementarlas), puede darte un error de abstract error code si las llamas desde un descendiente que no lo tenga implementado.

A lo mejor a alguien se le ocurre otra forma. Pero yo lo haría así

sukhur

Pues efectivamente se produce el error, en Camion porque no encuentra los métodos de Moto, y en Moto porque no encuentra los de Camion.

¿Como soluciono ésto?

tamat

La solución que te han dicho me parece una chapuza (con todos mis respetos).

Yo lo que hago es tener un método abstracto en la clase base que se llame GetType() que retorne un int, y luego hago un enum o unos defines para asignar un valor a cada clase.

Así cuando quieras hacer algo propio de camion hago:


if ( vec[0]->GetType() == CLASS_CAMION)
   ((Camion*)vec[0])->GetCM3();


Esta solución la he visto en muchos sitios y me parece la mejor, luego puedes activar el RTTI que sirve para preguntar de qué tipo es una instancia en C++ pero no se muy bien como va.
Por un stratos menos tenso

bnl

Yo creo q no tiene mucho sentido el enunciado.

Si el array de elementos de la clase base solo deberias llamar a los metodos propios de la clase padre. Si estamos hablando de vehiculos, no podrias decir  que te hiciera un caballito porque lo mismo es una moto que un camion.
Mi web: http://www.brausoft.com/
No sabían que era imposible, así que lo hicieron.

Pogacha

La verdad es que la solucion mas amiga de la POO es el uso de RTTI(real time type information) y moldeo dinamico (dynamic cast)

No queda bien claro el caso pero he de suponer que debe ser algo como esto:void Imprimir_Reporte(Vehiculo *elvehiculo)
{
   printf("Matricula: %s\n", elvehiculo->getMatricula());
   printf("Año: %d\n", elvehiculo->getAño());
   printf("Precio: %.2f\n", elvehiculo->getPrecio());
   printf("Motor: %s\n", elvehiculo->getMotor());

   Camion *elcamion = dynamic_cast<Camion>(elvehiculo)
   if(elcamion) {
      printf("Pma: %d\n", elcamion->getPma());
      printf("Longitud: %.2f\n", elcamion->getLongitud());
  }

   Moto *lamoto = dynamic_cast<Moto>(elvehiculo)
   if(lamoto) {
      printf("Cm3: %d\n", lamoto->getCm3());
      printf("VelPunta: %.2f\n", lamoto->getVelPunta());
  }
}

Esto mismo se puede hacer con un falso RTTI como propone tamat pero debes agregar a vehiculo
class Vehiculo
public:
enum Tipo { CAMION, AUTO };
virtual Tipo getType() = NULL;
...


y a moto y camion los correspondientes
virtual Tipo getType() { return MOTO; }
virtual Tipo getType() { return CAMION; }


con lo que el imprimir reporte se transforma en:
void Imprimir_Reporte(Vehiculo *elvehiculo)
{
   printf("Matricula: %s\n", elvehiculo->getMatricula());
   printf("Año: %d\n", elvehiculo->getAño());
   printf("Precio: %.2f\n", elvehiculo->getPrecio());
   printf("Motor: %s\n", elvehiculo->getMotor());

  switch(elvehiculo->getType())
  {
      case Vehiculo::CAMION:
        {
          Camion *elcamion = static_cast<Camion>(elvehiculo)
          printf("Pma: %d\n", elcamion->getPma());
          printf("Longitud: %.2f\n", elcamion->getLongitud());
        }
        break;
      case Vehiculo::MOTO:
        {
           Moto *lamoto = satic_cast<Moto>(elvehiculo)
           printf("Cm3: %d\n", lamoto->getCm3());
           printf("VelPunta: %.2f\n", lamoto->getVelPunta());
        }
        break;
   }
}


La solución de tener una clase abstracta con todas las funciones por mas que sean absurdas no es muy amiga de la POO, por que entonces, para que quieres heredar de ellas si la clase base ya tiene todas las funcionalidades que tu querias?

Saludos!

Fran

Cita de: "tamat"La solución que te han dicho me parece una chapuza (con todos mis respetos).

Yo lo que hago es tener un método abstracto en la clase base que se llame GetType() que retorne un int, y luego hago un enum o unos defines para asignar un valor a cada clase.

Así cuando quieras hacer algo propio de camion hago:


if ( vec[0]->GetType() == CLASS_CAMION)
   ((Camion*)vec[0])->GetCM3();


Esta solución la he visto en muchos sitios y me parece la mejor, luego puedes activar el RTTI que sirve para preguntar de qué tipo es una instancia en C++ pero no se muy bien como va.

El método 1 q he escrito es este. A mi, personalmente, me parece un coñazo. Tienes que estar haciendo para cada propiedad q tengas el mismo código. Me parece mucho más corto (aunq no sea muy ortodoxo segun vosotros) decir que todos los vehiculos tienen CM3 y que en principio es 0. Si te interesa para alguno de ellos saber cual es (las motos), lo redefines en esa clase en particular y ya está. De hecho a mi entender lo q estás diciendo es un absurdo. Segun tu el metodo de un clase figura sería algo asi como:

if ( vec[0]->GetType() == CLASSTRIANGULO)
   result=b * h * 0.5
else if .... = CLASSRECTANGULO
  result=b * h
else if......

Segun yo, defines metodo abstracto en clase figuras Area
y luego en cada clase hija pones su método de calculo . Metodo a todas luces (para mi) mas corto, mas racional y mas facilmente legible y escalable. Por ejemplo, si quieres insertar un nuevo tipo de vehiculo, con tu metodo hay que declararlo en esos IF (si tienes N propiedades y 3 vehiculos nuevos), 3N ifs nuevos, con el mio no tienes q hacer nada.

Fran

Cita de: "Pogacha"La verdad es que la solucion mas amiga de la POO es el uso de RTTI(real time type information) y moldeo dinamico (dynamic cast)

No queda bien claro el caso pero he de suponer que debe ser algo como esto:void Imprimir_Reporte(Vehiculo *elvehiculo)
{
   printf("Matricula: %s\n", elvehiculo->getMatricula());
   printf("Año: %d\n", elvehiculo->getAño());
   printf("Precio: %.2f\n", elvehiculo->getPrecio());
   printf("Motor: %s\n", elvehiculo->getMotor());

   Camion *elcamion = dynamic_cast<Camion>(elvehiculo)
   if(elcamion) {
      printf("Pma: %d\n", elcamion->getPma());
      printf("Longitud: %.2f\n", elcamion->getLongitud());
  }

   Moto *lamoto = dynamic_cast<Moto>(elvehiculo)
   if(lamoto) {
      printf("Cm3: %d\n", lamoto->getCm3());
      printf("VelPunta: %.2f\n", lamoto->getVelPunta());
  }
}

Esto mismo se puede hacer con un falso RTTI como propone tamat pero debes agregar a vehiculo
class Vehiculo
public:
enum Tipo { CAMION, AUTO };
virtual Tipo getType() = NULL;
...


y a moto y camion los correspondientes
virtual Tipo getType() { return MOTO; }
virtual Tipo getType() { return CAMION; }


con lo que el imprimir reporte se transforma en:
void Imprimir_Reporte(Vehiculo *elvehiculo)
{
   printf("Matricula: %s\n", elvehiculo->getMatricula());
   printf("Año: %d\n", elvehiculo->getAño());
   printf("Precio: %.2f\n", elvehiculo->getPrecio());
   printf("Motor: %s\n", elvehiculo->getMotor());

  switch(elvehiculo->getType())
  {
      case Vehiculo::CAMION:
        {
          Camion *elcamion = static_cast<Camion>(elvehiculo)
          printf("Pma: %d\n", elcamion->getPma());
          printf("Longitud: %.2f\n", elcamion->getLongitud());
        }
        break;
      case Vehiculo::MOTO:
        {
           Moto *lamoto = satic_cast<Moto>(elvehiculo)
           printf("Cm3: %d\n", lamoto->getCm3());
           printf("VelPunta: %.2f\n", lamoto->getVelPunta());
        }
        break;
   }
}


La solución de tener una clase abstracta con todas las funciones por mas que sean absurdas no es muy amiga de la POO, por que entonces, para que quieres heredar de ellas si la clase base ya tiene todas las funcionalidades que tu querias?

Saludos!

Respondido en lo anterior. ¿Para que tienes q hacer un CASE? . No veis q liais la programación sin necesidad de hacerlo?

Pogacha

Cita de: "Fran"Segun yo, defines metodo abstracto en clase figuras Area
y luego en cada clase hija pones su método de calculo . Metodo a todas luces (para mi) mas corto, mas racional y mas facilmente legible y escalable. Por ejemplo, si quieres insertar un nuevo tipo de vehiculo, con tu metodo hay que declararlo en esos IF (si tienes N propiedades y 3 vehiculos nuevos), 3N ifs nuevos, con el mio no tienes q hacer nada.
Pero eso no es POO!, ¿para que vas a heredar si con la base clase ya tienes todo lo que quieres?
Hay mil formas de hacer eso, muchas mas rapidas de codificar (incluso mas eficientes también) pero en la POO se sacrifica rendimiento y eficiencia para poder alcanzar objetivos mas altos los cuales solo se pueden lograr con disciplina, la misma que este paradigma nos presenta.
Saludos.

Fran

http://www.linuxjournal.com/article/3687

www.cs.tau.ac.il/~borens/courses/oop-03b/prez/oop_08.ppt

Extraido de este ultimo

"Our goal in polymorphism is to avoid checking the actual type of an object by using virtual methods "

Osease que me da q a lo mejor , la patata (para mi es asi) la estais plantenando vosotros. Estar checando de que tipo es , es una patata. Y demuestra no tener clara la teoria de OOP. Para mi y para muchos.

Fran

Cita de: "Pogacha"
Cita de: "Fran"Segun yo, defines metodo abstracto en clase figuras Area
y luego en cada clase hija pones su método de calculo . Metodo a todas luces (para mi) mas corto, mas racional y mas facilmente legible y escalable. Por ejemplo, si quieres insertar un nuevo tipo de vehiculo, con tu metodo hay que declararlo en esos IF (si tienes N propiedades y 3 vehiculos nuevos), 3N ifs nuevos, con el mio no tienes q hacer nada.
Pero eso no es POO!, ¿para que vas a heredar si con la base clase ya tienes todo lo que quieres?
Hay mil formas de hacer eso, muchas mas rapidas de codificar (incluso mas eficientes también) pero en la POO se sacrifica rendimiento y eficiencia para poder alcanzar objetivos mas altos los cuales solo se pueden lograr con disciplina, la misma que este paradigma nos presenta.
Saludos.

jajajajajajajaja. Mira. Leete un tratado serio de OOP.






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.