Programación I

Anuncio
Programación I
Unidad 6
Polimorfismo
Polimorfismo
•Permite diseñar e implementar sistemas
que sean extensibles con gran facilidad.
•Los programas se escriben para que
procesen objetos de forma genérica: objetos
de todas las clases existentes en una
jerarquía.
A
B
C
D
Polimorfismo
• Un puntero de tipo A puede apuntar a cualquier
objeto de sus subclases (no al contrario).
A=animales;
B=perros; C=gatos; D=leones;
•Tiene sentido:
¿Un perro es un animal? SI
A* a = new B(); // CORRECTO
¿Todos los animales son perros? NO
B* b = new A(); // INCORRECTO
Polimorfismo y métodos virtuales
Supongamos que la clase A contiene un método estático
p, y que las subclases de A redefinen dicho método:
C* objC = new C();
B* objB = new B();
A* objA = objB;
objA->p(); // (1)
objA = objC;
objA->p(); // (2)
Tanto en (1) como en (2) se ejecuta el método p de la
clase A.
La razón es que objA es de tipo A, y como el método es de
enlace estático, siempre se ejecuta el método de la clase a
la que pertenece la variable y no el de la clase del objeto
contenido en la variable (enlace dinámico-tiempo de
ejecución).
Polimorfismo y métodos virtuales
¿qué podríamos hacer para que se ejecute el método del
tipo del objeto contenido en la variable?
métodos virtuales
“Se determina el método a ejecutar en tiempo de
ejecución”
ENLACE DINÁMICO
(SÓLO POSIBLE CON PUNTEROS Y REFERENCIAS)
Sintaxis:
virtual tipo nombreMetodo(parámetros);
Convenio:
Poner virtual, además de en la clase base, en todas las
subclases directas o indirectas que redefinan el método.
Polimorfismo y métodos virtuales: ejemplo
class Base {
public:
virtual void p(){ShowMessage(“Clase base");}
};
class Hija:public Base {
public:
virtual void p(){ShowMessage(“Clase hija");}
};
class Nieta:public Hija {
public:
virtual void p(){ShowMessage(“Clase nieta");}
};
Base* b=new Hija();
b->p(); // p de la clase Hija
Hija* h = new Nieta();
h->p(); // p de la clase Nieta
Aunque en las subclases el método p no apareciera como virtual lo
sería igualmente.
Polimorfismo y métodos nuevos
Cuando una subclase añade nuevos métodos, si hacemos
uso del polimorfismo, no podemos invocarlos directamente:
hay que hacer “casting”.
class Base {
public:
virtual void p()
{ShowMessage(“Clase base");}
};
class Hija:public Base {
public:
virtual void p(){ShowMessage(“Clase hija");}
void p1(){ShowMessage(“Soy nuevo”);}
};
Base * b = new Hija(); b->p1(); // error de compilación
(Hija* b)->p1(); //se ejecuta el método p1 de la clase
Hija
Polimorfismo: Destructores
class Base{
private:
T* t; // objeto dinámico de la clase T
public:
Base(){t=new T(...);....}
.....
~Base(){delete t; t=NULL;}};
class Hija:public Base {
private:
M* m; // objeto dinámico de la clase M
public:
Hija():Base(){m=new M(...);...}
.....
~Hija(){delete m; m=NULL;}};
Base* b = new Hija(); delete b;
Se invoca al destructor de la clase Base !!! Dejamos sin borrar m !!!
SOLUCIÓN: EL destructor de la clase Base debe ser virtual.
En tal caso, primero se ejecutará la destructora de la clase Hija, y
después la de la clase Base.
Polimorfismo: clases abstractas
Una clase abstracta es una clase de la que no podemos tener
instancias (i.e. objetos).
Se usan como clases “tipo” de las cuales heredan otras clases.
Para indicar que una clase es abstracta basta introducir un
método virtual puro (o abstracto).
virtual tipo nombreMetodo(argumentos)=0;
Por ejemplo:
class Base {
public:
virtual void show()=0;
};
Una clase que herede de la clase Base debe implementar el método
show. En otro caso la subclase también se considerará abstracta.
Polimorfismo: Información de tipo en ejecución
La función typeid devuelve una referencia a un objeto de la clase
type_info. Los objetos de esta clase representan un tipo.
Sintaxis:
typeid(expresión) == typeid(tipo)
Ejemplos:
Grafico* graf = new Rectangulo(......);
if typeid(*graf)==typeid(Rectangulo)
ShowMessage(“cierto”);
else ShowMessage(“falso”);
Si la clase Grafico contiene al menos un método virtual (clase
polimórfica), se mostrará “cierto”, en otro caso se mostrará
“falso”.
Polimorfismo: Información de tipo en ejecución
Con clases polimórficas, typeid(*graf) devuelve el tipo del objeto
apuntado por graf en tiempo de ejecución. En otro caso devuelve el
tipo en tiempo de compilación.
La clase type_info tiene definidos los operadores “==“ y “!=“
Para utilizar typeid es necesario incluir el módulo typeinfo:
#include <typeinfo>
typeid(*a) con a == NULL genera una excepción.
Descargar