clase polimorfismo

21
Programación Orientada a Objetos (Clase 21.05.2015) Prof. J.Fiestas

Upload: raul-leonardo-huaman-p

Post on 29-Jan-2016

238 views

Category:

Documents


0 download

DESCRIPTION

Mineralogia

TRANSCRIPT

Page 1: Clase Polimorfismo

Programación  Orientada  a  Objetos  

 (Clase  21.05.2015)  

Prof.  J.Fiestas  

Page 2: Clase Polimorfismo

Programación  Orientada  a  Objetos  

3  principales  elementos  de  la    Programación  Orientada  a  Objetos:  

-­‐  Abstracción  de  Objetos    -­‐  Herencia  (y  composición)    -­‐  Polimorfismo  (funciones  virtuales)  

Page 3: Clase Polimorfismo

Programación  Orientada  a  Objetos  

ARBOL  

plantar  ()  cosechar()  

CLASE  

INTERFASE  

arbol lucuma; lucuma.plantar(); lucuma.cosechar();

(nombre  del)  OBJETO:    lucuma  

UML:  unified  modeling  language  

ABSTRACCIÓN  DE  OBJETOS:  

Page 4: Clase Polimorfismo

Programación  Orientada  a  Objetos  

HERENCIA  Y  COMPOSICION:  

VEHICULO  MOTORIZADO  

costo_de_seguro()  lista  de  repuestos()  

VEHICULO  Precio  

lista  de  repuestos()  

 BICICLETA  accesorios()  

lista  de  repuestos()    

AUTO  costo_de_seguro()  lista  de  repuestos()  

 

MOTOCICLETA  costo_de_seguro()  lista  de  repuestos()  

 

Page 5: Clase Polimorfismo

Programación  Orientada  a  Objetos  

POLIMORFISMO:  

PINTURA    

TECNICA  

OLEO    

TECNICA  

ACUARELA    

TECNICA  

ACRILICO    

TECNICA  

Permite  uXlizar  disXntos  métodos  con  el  mismo  nombre  a  traves  de  funciones  virtuales  

OLEO  EN  CANVAS  

 TECNICA  

OLEO  EN  PAPEL  

 TECNICA  

Page 6: Clase Polimorfismo

Programación  Orientada  a  Objetos  

//Instrument2.cpp  //  Inheritance  &  upcasXng  #include  <iostream>  using  namespace  std;  enum  note  {  middleC,  Csharp,  Eflat  };  //  Etc.  class  Instrument  {  public:  void  play(note)  const  {  cout  <<  "Instrument::play"  <<  endl;  }  };  //  Wind  objects  are  Instruments  //  because  they  have  the  same  interface:  class  Wind  :  public  Instrument  {  public:  //  Redefine  interface  funcXon:  void  play(note)  const  {  cout  <<  "Wind::play"  <<  endl;  }  };  void  tune(Instrument&  i)  {  //  ...  i.play(middleC);  }  

int  main()  {  Wind  flute;  tune(flute);  //  UpcasXng  }  ///:~    

UpcasNng  (conversión  hacia  arriba):    tune()  acepta  un  Instrument  por  referencia,  y  a  todo  lo  derivado  de  Instrument.  En  el  main(),  el  objeto  Wind  pasa  a  tune(),  sin  necesidad  de  un  casXng  

Polimorfismo:  

Page 7: Clase Polimorfismo

Programación  Orientada  a  Objetos  

El  problema:  El  output  del  programa  anterior  es  Instrument::play,  lo  que  no  es  lo  ideal,  ya  que  se  sabe  que  Wind  no  es  solo  un  Instrument  sino  uno  de  viento.  Deberia  imprimirse  Wind::play  

La  solución  en  C++:  C++  uXliza  virtual  para  estos  casos,  declarando  la  función  en  la  clase  base.  Solo  la  declaración  necesita  virtual  (no  la  definición).  Si  una  función  es  virtual  en  la  clase  base,  es  virtual  en  todas  las  clases  derivadas  Ahora  la  salida  es  Wind::play  

//Instrument3.cpp  //  Late  binding  with  the  virtual  keyword  #include  <iostream>  using  namespace  std;  enum  note  {  middleC,  Csharp,  Cflat  };  //  Etc.  class  Instrument  {  public:  virtual  void  play(note)  const  {  cout  <<  "Instrument::play"  <<  endl;  }  };  //  Wind  objects  are  Instruments  //  because  they  have  the  same  interface:  class  Wind  :  public  Instrument  {  public:  //  Override  interface  funcXon:  void  play(note)  const  {  cout  <<  "Wind::play"  <<  endl;  }  };  void  tune(Instrument&  i)  {  //  ...  i.play(middleC);  }  

int  main()  {  Wind  flute;  tune(flute);  //  UpcasXng  }  ///:~    

Polimorfismo:  

Page 8: Clase Polimorfismo

Programación  Orientada  a  Objetos  

//Instrument4.cpp  //  Extensibility  in  OOP  #include  <iostream>  using  namespace  std;  enum  note  {  middleC,  Csharp,  Cflat  };  //  Etc.  class  Instrument  {  public:  virtual  void  play(note)  const  {  cout  <<  "Instrument::play"  <<  endl;  }  virtual  char*  what()  const  {  return  "Instrument";  }  //  Assume  this  will  modify  the  object:  virtual  void  adjust(int)  {}      };  class  Wind  :  public  Instrument  {  public:  void  play(note)  const  {  cout  <<  "Wind::play"  <<  endl;    }  char*  what()  const  {  return  "Wind";  }  void  adjust(int)  {}        };  

class  Percussion  :  public  Instrument  {  public:  void  play(note)  const  {  cout  <<  "Percussion::play"  <<  endl;  }  char*  what()  const  {  return  "Percussion";  }  void  adjust(int)  {}  };    class  Stringed  :  public  Instrument  {  public:  void  play(note)  const  {  cout  <<  "Stringed::play"  <<  endl;  }  char*  what()  const  {  return  "Stringed";  }  void  adjust(int)  {}  };  

Polimorfismo:  

Page 9: Clase Polimorfismo

Programación  Orientada  a  Objetos  

class  Brass  :  public  Wind  {  public:  void  play(note)  const  {  cout  <<  "Brass::play"  <<  endl;  }  char*  what()  const  {  return  "Brass";  }  };  class  Woodwind  :  public  Wind  {  public:  void  play(note)  const  {  cout  <<  "Woodwind::play"  <<  endl;  }  char*  what()  const  {  return  "Woodwind";  }  };  

Aca  se  crea  otro  nivel  de  herencia,  pero  la  clase  virtual  se  manXene  virtual  en  todas  las  clases  derivadas  Las  clases  Brass  y  Woodwind  pueden  llamar  a  la  función  adjust  de  la  clase  base  

Polimorfismo:  

Page 10: Clase Polimorfismo

Programación  Orientada  a  Objetos  

int  main()  {  Wind  flute;  Percussion  drum;  Stringed  violin;  Brass  flugelhorn;  Woodwind  recorder;  tune(flute);  tune(drum);  tune(violin);  tune(flugelhorn);  tune(recorder);  f(flugelhorn);  }  ///:~  

tune()  realiza  upcasXng  en  cada  Xpo  diferente  de  objeto,  obteniendo  siempre  el  resultado  correcto.  

//  IdenXcal  funcXon  from  before:  void  tune(Instrument&  i)  {  //  ...  i.play(middleC);  }  //  New  funcXon:  void  f(Instrument&  i)  {  i.adjust(1);  }  //  UpcasXng  during  array  iniXalizaXon:  Instrument*  A[]  =  {  new  Wind,  new  Percussion,  new  Stringed,  new  Brass,  };  

Polimorfismo:  

Page 11: Clase Polimorfismo

Programación  Orientada  a  Objetos  

Enlace  dinámico:  

Cuando  se  enlaza  el  llamado  de  una  función  en  el  main()  a  su  declaración,  se  hace  enlace  por  el  compilador  (enlace  temprano).  Por  ello,  en  el  ejemplo  anterior,  se    llaman  originalmente  a  las  funciones  de  la  clase  base.  La  solución  la  dan  las  funciones  virtuales  a  través  del  enlace  dinámico,  o  tardío.    Virtual,  le  dice  al  compilador  que  no  debe  realizar  enlace  temprano.  Es  decir,  si  se  llama  play()  para  un  objeto  de  Xpo  Brass,  a  través  de  una  direccion  a  la  clase  base  Instrument,  se  hara  el  enlace  correcto.  

Con  ese  objeXvo,  el  compilador  crea  una  tabla  (VTABLE)  para  cada  clase  que  contenga  funciones  virtuales.  En  esa  tabla  se  listan  las  direcciones  de  las  funciones  virtuales,  a  las  cuales  se  les  asigna  un  puntero  (vpointer,  VPTR),  que  apunta  a  la  VTABLE  de  ese  objeto  (al  hacer  un  llamado  polimórfico),  llamando  asi  a  la  función  correcta  (enlace  dinámico)  

Page 12: Clase Polimorfismo

Programación  Orientada  a  Objetos  

Enlace  dinámico:  Vector  A  de  punteros  a  Instrument,  incluye  todas  sus  clases  derivadas  

Cada  vez  que  se  crea  una  clase  con  funciones  virtuales  se  crea  una  VTABLE  para  esa  clase,  con  las  direcciones  de  las  funciones  declaradas  virtuales  (de  no  ser  virtuales  se  usara  la  funcion  de  la  clase  base:  adjust()  in  Brass)  

Entonces  uXliza  el  puntero  virtual  (VPTR)  en  la  clase,  que  apunta  a  la  direccion  inicial  de  la  tabla.    Una  vez  inicializado  en  VTABLE,  se  define  el  Xpo  de  objeto  que  este  es.  

Page 13: Clase Polimorfismo

Programación  Orientada  a  Objetos  

Por  ejemplo,  el  compilador  inicia  con  el  puntero  de  Xpo  Instrumento,  que  apunta  a  la  direccion  inicial  del  objeto  de  Xpo  Brass.  El  VPTR  apunta  a  la  direccion  inicial  de  VTABLE,  con  direccion  de  funciones  en  un  orden  específico  (el  mismo  orden  para  todas  las  VTABLE)  La  función  adjust  esta  ubicada  en  VPTR+2  

Page 14: Clase Polimorfismo

Programación  Orientada  a  Objetos  

Importante:  UpcasXng  funciona  solo  con  direcciones,  ya  que  si  el  compilador  Xene  un  objeto,  el  Xpo  ya  esta  definido  y  no  se  usará  enlace  dinámico    En  p1-­‐>speak()  y  p2.speak()  son  usadas  direcciones,  o  sea  el  Xpo  no  se  conoce,  y  se  hace  uso  de  funciones  virtuales.    En  p3.speak()  no  hay  ambiguedad,  y  es  una  clase  base,  no  derivada,  y  se  aplica  enlace  temprano.  

//Early.cpp  //  Early  binding  &  virtual  funcXons  #include  <iostream>  #include  <string>  using  namespace  std;  class  Pet  {  public:  virtual  string  speak()  const  {  return  "";  }  };  class  Dog  :  public  Pet  {  public:  string  speak()  const  {  return  "Bark!";  }  };  int  main()  {  Dog  ralph;  Pet*  p1  =  &ralph;  Pet&  p2  =  ralph;  Pet  p3;  //  Late  binding  for  both:  cout  <<  "p1-­‐>speak()  =  "  <<  p1-­‐>speak()  <<endl;  cout  <<  "p2.speak()  =  "  <<  p2.speak()  <<  endl;  //  Early  binding  (probably):  cout  <<  "p3.speak()  =  "  <<  p3.speak()  <<  endl;  }  ///:~  

Page 15: Clase Polimorfismo

Programación  Orientada  a  Objetos  

Clases  Abstractas:  

La  clase  base  abstracta  representa  solo  una  interfase  comun  a  su  clase  derivada  (no  es  posible  crear  un  objeto  de  la  clase  base).  En  este  caso  es  obligación  definir  las  funciones  en  las  clases  derivadas  (en  caso  contrario  seran  tambien  abstractas).  

Page 16: Clase Polimorfismo

Programación  Orientada  a  Objetos  

Clases  Abstractas:  //Instrument5.cpp  //  Pure  abstract  base  classes  #include  <iostream>  using  namespace  std;  enum  note  {  middleC,  Csharp,  Cflat  };  //  Etc.  class  Instrument  {  public:  //  Pure  virtual  funcXons:  virtual  void  play(note)  const  =  0;  virtual  char*  what()  const  =  0;  //  Assume  this  will  modify  the  object:  virtual  void  adjust(int)  =  0;  };  //  Rest  of  the  file  is  the  same  ...  

virtual  void  f()  =  0;  

Objetos  de  clase  Instrument,  no  Xenen  un  significado  real.  Una  declaración  abstracta  es  como    

Page 17: Clase Polimorfismo

Programación  Orientada  a  Objetos  

//AddingVirtuals.cpp  //  Adding  virtuals  in  derivaXon  #include  <iostream>  #include  <string>  using  namespace  std;  class  Pet  {  string  pname;  public:  Pet(const  string&  petName)  :  pname(petName)  {}  virtual  string  name()  const  {  return  pname;  }  virtual  string  speak()  const  {  return  "";  }    };  class  Dog  :  public  Pet  {  string  name;  public:  Dog(const  string&  petName)  :  Pet(petName)  {}  //  New  virtual  funcXon  in  the  Dog  class:  virtual  string  sit()  const  {  return  Pet::name()  +  "  sits";  }  string  speak()  const  {  //  Override  return  Pet::name()  +  "  says  'Bark!'";  }  };  

Herencia  y  funciones  virtuales  en  clases  derivadas:    Pet  conXene  dos  funciones  virtuales:  speak()  y  name()  Dog  agrega  una  tercera  función  virtual  sit()  y  sobrecarga  la  definición  de  speak()    

Page 18: Clase Polimorfismo

Programación  Orientada  a  Objetos  

int  main()  {  Pet*  p[]  =  {new  Pet("generic"),new  Dog("bob")};  cout  <<  "p[0]-­‐>speak()  =  "  <<  p[0]-­‐>speak()  <<  endl;  cout  <<  "p[1]-­‐>speak()  =  "  <<  p[1]-­‐>speak()  <<  endl;  //!  cout  <<  "p[1]-­‐>sit()  =  "  //!  <<  p[1]-­‐>sit()  <<  endl;  //  Illegal  }  ///:~  

El  compilador  localiza  speak()  en  el  mismo  lugar  del  VTABLE  para  Dog  y  Pet.  Pero  como  p[]  es  un  puntero  a  la  clase  objeto  Pet,  la  que  Xene  solo  las  funciones  speak()  y  name(),  solo  permiXra  llamar  a  esas  funciones.    Una  solución  es  hacer  casXng  al  puntero:          Pero  hay  que  saber  el  Xpo  del  puntero  para  ello  

((Dog*)p[1])-­‐>sit()  

Page 19: Clase Polimorfismo

Programación  Orientada  a  Objetos  

Object  slicing:  

Que  pasa  si  pasamos  objetos  por  valor  a  las  funciones  virtuales?  Normalmente  se  usan  punteros,  y  pasan  direcciones  que  Xenen  el  mismo  tamaño,  independientemente  a  si  son  clases  bases  o  derivadas  (que  son  normalmente  objetos  mas  grandes)  Si  se  hace  upcasXng  a  un  objeto  (por  valor)  y  no  a  un  puntero  o  referencia.  El  objeto  es  cortado  (sliced)  

//ObjectSlicing.cpp  #include  <iostream>  #include  <string>  using  namespace  std;  class  Pet  {  string  pname;  public:  Pet(const  string&  name)  :  pname(name)  {}  virtual  string  name()  const  {  return  pname;  }  virtual  string  descripXon()  const  {  return  "This  is  "  +  pname;  }  };  class  Dog  :  public  Pet  {  string  favoriteAcXvity;  public:  Dog(const  string&  name,  const  string&  acXvity)  :  Pet(name),  favoriteAcXvity(acXvity)  {}  string  descripXon()  const  {  return  Pet::name()  +  "  likes  to  "  +  favoriteAcXvity;  }  };  

Page 20: Clase Polimorfismo

Programación  Orientada  a  Objetos  

void  describe(Pet  p)  {  //  Slices  the  object  cout  <<  p.descripXon()  <<  endl;  }  int  main()  {  Pet  p("Alfred");  Dog  d("Fluffy",  "sleep");  describe(p);  describe(d);  }  ///:~  

La  función  describe()  pasa  un  objeto  de  Xpo  Pet  por  valor.  Este  llama  la  función  virtual  descripXon()  para  el  objeto  Pet.  En  main(),  ambos  llamados  usaran  la  version  de  descripXon()  de  la  clase  base.    Ya  que  describe()  acepta  un  objeto  Pet,  esta  va  a  transformar  al  objeto  derivado  de  Pet  en  un  objeto  Pet,  pero  solo  copiando  la  parte  Pet  del  objeto  

Page 21: Clase Polimorfismo

Programación  Orientada  a  Objetos  

Ejercicio:  Escribir  un  programa  simple  en  C++  uXlizando  polimorfismo,  que  describa  el  diagrama  de  herencia  de  la  pagina  4  de  la  clase  de  hoy,  y  que  ayude  al  usuario  a  decidir  que  Xpo  de  vehiculo  comprar  de  acuerdo  a  la  canXdad  de  dinero  disponible  durante  el  primer  año.  Para  ello:  -­‐  Declarar  la  funcion  lista_de_respuestos()  como  virtual,  que  retorne  una  lista  de  3  repuestos  con  sus  respecXvos  costos,  dependiendo  del  vehiculo  que  se  trate.  -­‐  Definir  una  funcion  virtual  costo_de_seguro(),  en  el  caso  de  vehiculos  motorizados  (clase  derivada)  que  retorne  el  costo  de  seguro  mensual  -­‐  Definir  ademas  una  funcion  virtual  que  calcule  el  costo  de  repuestos  por  año,  asumiendo  el  consumo  de  un  Xpo  de  repuesto  por  mes.  -­‐  Una  funcion  externa  ayudara  a  decidir  que  Xpo  de  vehiculo  puedo  comprar  de  acuerdo  a  una  canXdad  de  dinero  ingresada  por  el  usuario,  y  que  retorne:  el  precio  del  vehiculo  elejido,  los  costos  de  repuestos  por  año,  y  los  costos  de  seguro  anual  en  caso  sea  un  vehiculo  motorizado.    Definir  los  objetos  en  el  main()  como  punteros  de  clase  Vehiculo,  por  ejemplo:  Vehiculo  *p  =  new  Bicicleta(precio,capacidad);