Publicado el 9 de Mayo del 2017
1.703 visualizaciones desde el 9 de Mayo del 2017
92,5 KB
7 paginas
Creado hace 13a (04/07/2011)
Herencia y Polimorfismo
Introducción
• Se pueden definir jerarquías de clases, con
clases generales que definen el
comportamiento común a unos objetos y
clases específicas que sólo añaden o
redefinen el comportamiento propio, único,
de ese objeto respecto a la clase general.
• Clases bases y clases derivadas.
Curso de programación de C/C++
57
Curso de programación de C/C++
58
Ejemplos (I)
• Clase Persona (fecha nac., DNI, dir., tel.)
– Jefe (despacho, incentivos, ...)
– Vendedor (área, clientes,...)
– Secretarios
• Clase Forma: área (?), perímetro (?), color
– Rectángulo: dos lados, área, perímetro.
– Cuadrado: un lado, área, perímetro.
– Elipse: dos radios, área
– Circulo: Un radio, área, circunferencia
• Clasificación Animales (“es un ..”)
Ejemplos (II)
• Clase Vehículos: Peso, Potencia, Cilindrada
– Coches: Nº puertas, extras
• Monovolúmenes
• Deportivos.
• Furgonetas
– Camiones: PMA, Tara, Nº ejes.
• Rígidos
• Con remolque
– Motocicletas.
• Con matrícula
• Sin matrícula
Curso de programación de C/C++
59
Curso de programación de C/C++
60
Control de Acceso
Herencia
• Hay tres posibilidades respecto a la Base:
– Private: Solo se usan en la clase en cuestión.
– Protected: Se usan en esa clase y sus hijas.
– Public: Se puede usar fuera de la clase.
• Se aplica el más restrictivo entre el definido
en la clase base y el de acceso a la misma.
• Ej: class derivada: public base { ... }
• Se hereda todo, atributos y métodos.
• Con las restricciones de acceso comentadas.
• Si un método cambia su comportamiento
puede redefinirse. Puede invocar al padre:
cuadrado::imprimir () {
forma::imprimir();
cout << “ con lado “ << lado;
• Si no se redefine usa el método del padre.
Curso de programación de C/C++
61
Curso de programación de C/C++
62
1
Sustitución de métodos
class D: public B { … };
• Clase D puede reutilizar, extender o crear su
propia definición de método M de B
• Para sustituir la implementación de M de B,
lo define de nuevo
• Si lo extiende,
– desde M de D puede invocar M de B
• Pero usando el operador de ámbito B::M
• Si desea reutilizarlo no debe hacer nada.
Herencia Múltiple
• Hereda de varias clases a la vez.
cuad: public rect, public poly
{... };
• Es complejo y ambiguo. Un método puede
estar definido en varias clases padre.
• Luego lo ampliaremos, aunque debe evitarse.
Curso de programación de C/C++
63
Curso de programación de C/C++
64
Constructores y Destructores
• Los objetos se construyen de más general a
menos y se destruyen de forma inversa.
• Sino podría faltar información necesaria.
• Si tienen parámetros se le pasan:
cuad::cuad(lado l) :
rect(l, l), poly(4)
{... };
Constructor de la clase derivada
class D: public B { … };
• En la lista de iniciación del constructor de la clase D
– Invoca constructor B antes que los de miembros de datos de D
(m1,...)
– Al fin y al cabo, un objeto D “esconde” a un objeto B. Primero
se construye B y luego D
D(args. constructor de D) : B(args. constructor de B), m1(...), ... {};
Curso de programación de C/C++
65
Curso de programación de C/C++
66
Un D es un B, pero un B no es un D
• Las aplicaciones trabajan con B, D1, D2, ...
– Comportamiento cambia si se usan punteros o no
• Trabajando directamente con objetos
– Asignar objeto B a D da error de compilación →
objeto B no es D
– Asignar objeto D a B → OK pero se produce slicing
• En la copia se pierde toda la info. del objeto asociada a
clase D
• En la mayoría de los casos, no es lo que pretendía el
programador
Un D es un B, pero un B no es un D
• Trabajando con punteros o referencias a objetos
// OK; trivial
// OK; trivial
// error de compilación: B no es D
// OK: objeto D es de la clase B
B *pB = &objB;
D *pD = &objD;
D *pD = &objB;
B *pB = &objD;
B *pB = &objD;
D *pD = pB;
• Otro ejemplo de uso de punteros a objetos
// error de compilación, pero correcto →
// uso de dynamic_cast
Curso de programación de C/C++
67
Curso de programación de C/C++
68
2
Invocación de métodos
• B tiene métodos M1 y M2
• D derivada de B redefine/sustituye M2
• Ejemplos de invocación a través de punteros:
D *pD = &objD; B *pB = &objB; B *pX = &objD;
pD->M1(...);
pD->M2(...);
pB->M1(...);
pB->M2(...);
pX->M1(...);
pX->M2(...);
// M1 de B
// M2 de D; CASO 1
// M1 de B
// M2 de B
// M1 de B
// M2 de B; CASO 2≠CASO1 ¿SORPRESA?
Invocación de métodos
B *pX = &objD;
• Comportamiento extraño: pX->M2(...) debería
ejecutar M2 de D
– Resultado de invocar método depende de puntero
• Si lista de punteros a B que contiene objetos
derivados de B: D1,D2...
– Comportamiento razonable: ejecuta M2 de derivado →
polimorfismo
Curso de programación de C/C++
69
Curso de programación de C/C++
70
Polimorfismo (I)
Polimorfismo (II)
• Hay que tener presente que un director es
un empleado, pero no a la inversa:
Empleado Pepe;
Director D;
Pepe = D; // Bien
D = Pepe; // Mal
• ¿Pero que pasa si tenemos un vector de
empleados y no queremos que pierdan su
comportamiento (vendedor, jefe, contable)?
• La idea del polimorfismo es tratar de la
misma manera objetos distintos.
if (Fin de Año)
for (int i=0; i < n; i++)
vect_empleados[i].incr_salario();
//Directores un 20%, otros un 10%
Curso de programación de C/C++
71
Curso de programación de C/C++
72
Métodos Virtuales
• Esto se consigue con los Métodos Virtuales.
• Se define un vector de personas, pero a la hora de
acceder a cada una de ellas se comportan según lo
que sea: Polimorfismo.
• Funciona sólo con Punteros y Referencias.
• Cada clase tiene estos métodos redefinidos y en
ejecución se mira el tipo del objeto y se invoca al
método correspondiente.
• Delante del método se pone virtual.
• Si una clase no lo redefine, se sube en la jerarquía
hasta encontrar la definición.
Métodos virtuales
• Clase polimórfica: al menos un método M virtual
• Invocación a M mediante puntero (B *b) se
resuelve en ejecución
– Ligadura dinámica (dynamic binding)
– Si redefinida en clase del objeto (D), usa esa versión
– Sino la de la clase base directa de D, si la hay, y así hasta B
– Con polimorfismo mismo comportamiento b→M y d→M (D *d)
• d→M se comporta igual sea M polimórfico o no
– Invocación con operador de ámbito no es polimórfica (b→B::M)
Curso de programación de C/C++
73
Curso de programación de C/C++
74
3
Destructores Virtuales
• Los destructores pueden ser virtuales
virtual ~forma();
• Ejemplo en que es necesario:
forma * lista[MAX];
lista[0] = new rectangulo();
lista[1] = new circulo();
....
for (i=0; i<MAX; i++)
delete lista[i];
Destructores virtuales
• Necesidad de incluir destructor virtual en clase base
virtual ~C() { }
polimórfica:
– Incluso aunque clase B no tenga nada que destruir
– Puede (o podrá) haber clases derivadas que tengan que hacerlo
• Si no destructor virtual, problema al destruir objeto
mediante B*
– Se invoca el destructor de B en vez del destructor de D
• Los constructores no pueden ser virtuales
– Si se necesita una funcionalidad de ese tipo hay que programarla
• “Constructores virtuales”
Curso de programación de C/C++
75
Curso de programación de C/C++
76
Polimorfismo vs plantillas
• Capacidad de tratar uniformemente objetos de
distintas clases
– Incluso nuevas clases futuras
• Plantillas proporcionan polimorfismo estático
– En compilación se decide destino de llamada a función
• Polimorfismo dinámico:
– Determinar en tiempo de ejecución destino de llamada
a función
Clases abstractas
• Si en cierto nivel de la jerarquía no tiene
sentido se usan funciones virtuales Puras:
virtual void forma::area() = 0;
• Estas clases son abstractas y no pueden
instanciarse. Las clases derivadas deberán
implementar obligatoriamente todas estas
funciones, sino son clases abstractas también
Curso de programación de C/C++
77
Curso de programación de C/C++
78
Clases abstractas
• A menudo, no tiene sentido crear objetos de una
cierta clase base: Clase Abstracta
– La clase no está concebida como un molde para crear
objetos, es un contenedor de funcionalidad común
• Clase abstracta: tiene funciones virtuales puras
virtual void imprimir() = 0;
• Derivada debe implementar todas las FVPs
– Sino será también abstracta
• Clase abstracta con sólo FVPs define una interfaz
– Clases derivadas sólo heredan interfaz
Clases Abstractas
• Ejemplo
forma F; //NO.
forma *F; //SI
• Las referencias también son válidas.
func(forma &F)
{F.area(); //SI}
Main() {
cuadrado cuad;
func(cuad);...
Curso de programación de C/C++
79
Curso de programación de C/C++
80
4
Tipos de herencia
• Reutilización de código
– También se puede lograr mediante composición
• En vez de D es un B, D contiene un miembro de datos B
• Aspecto con cierta polémica: Mejor como atributos
• Polimorfismo: Tratamiento uniforme de
diversos objetos
– Mismo código maneja distintos tipos de clases
• Incluso nuevas clases que no existían cuando se programó
Tipos de herencia
• Según el grado de funcionalidad que se hereda
– Herencia de la implementación
• Más orientada hacia la reutilización
– Herencia de la interfaz
• Más orientada hacia el polimorfismo
• Según la cardinalidad de la herencia
– Simple: Clase sólo puede derivar de una clase base
– Múltiple: Clase puede derivar de múltiples clases
base
Curso de programación de C/C++
81
Curso de programación de C/C++
82
Tipos de herencia
• Lenguaje C++:
– No distingue entre herencia de implementación y de
interfaz. Debe hacerlo el programador
– Proporciona herencia múltiple
• Java
– Distingue entre herencia de implementación y de
interfaz
– Provee herencia simple de implementación y
múltiple de interfaz
Control de acceso:
Recapitulación funciones miembro
• Clase B Abstracta con funciones miembro
M1(FNV), M2 (FV) y M3 (FVP)
– pB (tipo B*) apunta a objeto de clase D
• Acción asociada a pB→MX():
– M1 no sustituido por D:
– M1 sustituido por D:
– M2 no susti
Comentarios de: Curso de programación de C/C++ - Herencia y Polimorfismo (0)
No hay comentarios