TEMA 5
Herencia Mltiple
Facultad de Informtica Universidad de Murcia
ndice
1.- Introduccin 2.- Utilidades de la herencia mltiple 3.- Problemas con la herencia mltiple.
Colisin de nombres Herencia repetida Conflicto cuando hay comparticin Conflicto cuando hay duplicacin
1.- Introduccin
Las clases pueden necesitar mas de una clase padre Ms difcil de usar e implementar que la herencia simple. Algunos consideran que produce ms inconvenientes que ventajas. Segn B. Meyer:
No puedo pensar en una aplicacin seria escrita en Eiffel que no use la herencia mltiple en un modo significativo Para discutir cuestiones conceptuales sobre H.M. es necesario considerar el doble aspecto de la herencia: subtipos y extensin modular
3
S es una especializacin de R MATH incluye un paquete de rutinas matemticas STORABLE ofrece servicios de persistencia de objetos
4
menu
MenuItem ejecutar
ii) Los mens contienen submens (Men compuesto) 1) Cambiar el tipo de la coleccin MENU TREE [OPCION_MENU] provocara muchos cambios 2) Aprovechar la implementacin de i) con herencia mltiple
5
menu
MenuItem ejecutar
Ejemplo2:
PROFESOR
PROFESOR_AYUDANTE
CUENTA_AHORRO
CUENTA_CORRIENTE
SOLUCIN:
Con herencia mltiple
CUENTA_ BANCARIA
CUENTA_ AHORRO
CUENTA_ CORRIENTE
CUENTA_ AHORRO
CUENTA_ CORRIENTE
NUEVA_CUENTA
SOLUCIN:
Con herencia mltiple
CUENTA_ BANCARIA
CUENTA_ AHORRO
CUENTA_ CORRIENTE
CUENTA_ AHORRO
CUENTA_ CORRIENTE
NUEVA_CUENTA
NUEVA_CUENTA
SOLUCIN:
Con herencia mltiple
CUENTA_ BANCARIA
CUENTA_ AHORRO
CUENTA_ CORRIENTE
CUENTA_ AHORRO
CUENTA_ CORRIENTE
NUEVA_CUENTA
NUEVA_CUENTA
SOLUCIN:
Con herencia mltiple
CUENTA_ BANCARIA
CUENTA_ AHORRO
CUENTA_ CORRIENTE
CUENTA_ AHORRO
CUENTA_ CORRIENTE
NUEVA_CUENTA
NUEVA_CUENTA
11
CHAR
INTEGER
Soluciones:
OPCION A Magnitude
Char
Integer
Complejo
12
Un rbol es una lista, la lista de sus hijos, pero tambin es un elemento potencial de la lista (un subrbol de otro rbol) Un rbol es una lista que es tambin un elemento de la lista
LIST permite obtener los hijos de un nodo, aadir/eliminar un hijo,... LINKABLE permite obtener el valor de un nodo, su hermanos, su padre, aadir un hermano...
15
TREE[G] grficamente
A B D E C B A 2
ARBOL es_un NODO valor siguiente cabeza numElementos ARBOL es_una LISTA C 0
2 D 0 E 0
16
C) Herencia de Estructura:
Se desea que una clase posea ciertas propiedades adems de la abstraccin que representa.
NUMERIC COMPARABLE DIAGRAMA STORABLE
INTEGER
DIAGRAMA_CLASES
D) Herencia de Facilidades:
Existen clases que existen con el nico propsito de ofrecer unos servicios a sus descendientes
MATH A ASCII A ITERATOR A
17
PILA_FIJA [G]+
PILA_ENLAZADA [G]+
La clase PILA_FIJA [G] slo exporta las caractersticas exportadas por PILA [G] y oculta las propiedades de ARRAY [G]. La clase PILA_ENLAZADA [G] slo exporta las caractersticas exportadas por PILA [G] y oculta las propiedades de LINKED_LIST [G].
18
PILA_FIJA [G]+
PILA_ENLAZADA [G]+
HERENCIA DE IMPLEMENTACIN La clase PILA_FIJA [G] slo exporta las caractersticas exportadas por PILA [G] y oculta las propiedades de ARRAY [G]. La clase PILA_ENLAZADA [G] slo exporta las caractersticas exportadas por PILA [G] y oculta las propiedades de LINKED_LIST [G].
19
class PILA_FIJA [G] inherit PILA [G] ARRAY [G] export {NONE} all rename put as array_put, make as array_make, count as capacity end creation make feature count: INTEGER; --hace efectiva como atributo una --caracterstica diferida make (n: INTEGER) is require tamao_no_negativo: n>=0; do array_make (1,n) ensure capacidad: capacity = n; vacia: count = 0 end
20
full: BOOLEAN is do --Est llena la representacin de la pila? Result:= (count = capacity) end; put (x: G) is -- Pone x en la cima de la pila require not full do count:= count + 1; array_put (x, count) end; invariant count>=0 ; count <= capacity ... end -- PILA_FIJA [G]
21
Problema en ejecucin
Sea la declaracin p: PILA_FIJA [INTEGER] entonces p.array_put (32,45) provocara error en tiempo de compilacin.
Herencia de implementacin
ARRAY [G] PILA [G]*
PILA_FIJA [G]+
full: BOOLEAN is do Result:= (count = capacity) end; put (x: G) is do count:= count + 1; array_put (x, count) end;
23
ARRAY [G]
imp
PILA_FIJA [G]+
full: BOOLEAN is do full: BOOLEAN is do Result:= (count = capacity) Result:= (count = imp.capacity) end; end; put (x: G) is do put (x: G) is do count:= count + 1; count:= count + 1; array_put (x, count) imp.put (x, count) end; end;
Toda manipulacin de la representacin requiere una llamada a una caracterstica de ARRAY con imp como receptor. 24
26
C++:
herencia privada class Pila: private Array{...};
Java:
throw new UnsupportedOperationException(); invocar con super a las propiedades del padre class Pila extends Array{ public void add(int pos, Object valor) { throw new UnsupportedOperationException(); } public void push(Object valor){ super.add(tope,valor); } 27 }
Una figura compuesta es una figura Una figura compuesta es una lista de figuras
28
visualizar girar
LISTA[FIGURA] start after forth visualizaris do girar() is do from start until after loop item.visualizar item.girar() forth end end
29
Simple operacion
Poligono dibujar
FiguraCompuesta dibujar componentes: LINKED_LIST[FIGURA] dibujar is do from componentes.start until componentes.after loop componentes.item.dibujar componentes.forth end 31 end
vs Herencia mltiple
LINEAR_ITERATOR*
redefine coleccion
FIGURA_COMPUESTA
FIGURA_COMPUESTA_ITERATOR*
visualizar is local iv: VISUALIZAR_ITERATOR do !!iv.make(Current) action + iv.forEach end VISUALIZAR_ITERATOR action (f: FIGURA) is do f.visualizar end
32
LINEAR_ITERATOR*
redefine coleccion
FIGURA_COMPUESTA
FIGURA_COMPUESTA_ITERATOR*
rotar is local ir: ROTAR_ITERATOR do !!ir.make(Current) action + ir.forEach end VISUALIZAR_ITERATOR action (f: FIGURA) is do f.visualizar end
action +
...
ROTAR_ITERATOR
action (f: FIGURA) is do f.rotar end
33
deferred class FIGURA_COMPUESTA_ITERATOR inherit LINEAR_ITERATOR [FIGURA_COMPUESTA] redefine coleccion end creation make feature coleccion: FIGURA_COMPUESTA -- Coleccin sobre la que itera -- (lista de figuras) end -- antes era Linear_List[G]
class VISUALIZAR_ITERATOR inherit FIGURA_COMPUESTA_ITERATOR redefine action end creation make feature action(f: FIGURA) is do f.visualizar end end 34
class FIGURA_COMPUESTA inherit FIGURA LINKED_LIST[FIGURA] feature ... visualizar is local iv: VISUALIZAR_ITERATOR do !!iv.make (Current) iv.forEach end ... end -- coleccin:= Figura_compuesta actual
NO HAY NADA MALO EN TENER CLASES TAN PEQUEAS NO ES ACEPTABLE PASAR RUTINAS COMO ARGUMENTOS 35 (B. Meyer)
{f} A C
B {f}
Solucin: Renombrar [y redefinir]
A B D
{at, f} C
Solucin: compartir o duplicar?
36
B {f}
No hay colisin de nombres si: i) colisiona una rutina diferida con otra efectiva ii) hay herencia repetida con comparticin
37
Versin
C {nf, g, h}
C C C
B B B
nf g h
f g h
* Ejercicio 1:
A {f} rename f as g B {g}
* Ejercicio 2:
A {f} rename f as g redefine g B {g}
oa: A; ob: B !!ob oa:= ob oa.f -- {} oa.g -- {error t.c.} ob.f -- {error t.c.} ob.g -- {}
oa: A; ob: B !!ob oa:= ob oa.f -- {} oa.g -- {error t.c.} ob.f -- {error t.c.} ob.g -- {}
41
* Ejercicio 3:
B {f, g}
rename f as h redefine h
{h, i }
Clase B B C C C Nombre final f g h g i
ob: B; oc: !!ob; ob.f () ob.g() ob:= oc ob.f () ob.i () oc.h () oc.f ()
42
Ejercicio 4
class C inherit A rename f as g; B rename f as h; redefine h; feature h is do end f is do end end
oa: A; ob: B; oc: C; !!oc; oc.f; oc.g; oc.h; oa:= oc; oa.f; oa.g; ob:= oc; ob.f; ob.h;
43
{f}
{f}
class C: private A, private B { public: void af ( ) {return A::f ()}; void bf ( ) {return B::f ()}; // reexportar las otras funciones de A y B // no renombradas ... 44 }
C
C* oc c -> A::f ( ) c- > B::f ( )
{f ()} fC
B* pb = pc;
pa -> f (); pb -> f (); pc -> f () Todos los mensajes invocan a C::f() !!! y la redefinicin de ambas funciones con una nica funcin f en C sera errneo porque a pesar del nombre comn las funciones f no estn relacionadas.
45
A1*
B1*
Ejemplo:
quiero redefinir los mtodos de las clases bases y mantener los dos.
Loteria ObjetoGrafico
virtual void draw()
Ejemplo:
quiero redefinir los mtodos de las clases bases y mantener los dos.
class Lloteria:public Loteria{ virtual int drawLoteria()=0; int draw() { return drawLoteria(); //redefine Loteria::draw } }; class OObjetoGrafico: public ObjetoGrafico{ virtual void drawGrafico()=0; void draw(){ drawGrafico(); //redefine ObjetoGrafico::draw } }; class SimuladorLoteria: public LLoteria, public OObjetoGrafico{ //... int drawLoteria(); //redefine y cambia el nombre de Loteria::draw void drawGrafico(); //redefine y cambia el nombre de };
//ObjetoGrafico::draw 48
{at, f} C
PROFESOR
{ingresos, ...}
1) Cualquier subconjunto de f1, .., fn heredado bajo el mismo nombre final genera una nica caracterstica en D (COMPARTICIN) 2) Cualesquiera dos de las f1, .., fn heredadas bajo diferente nombre, generan caractersticas diferentes en D (DUPLICACIN) El primer caso es lo que normalmente se necesita
52
{f}
f no provoca conflicto (comparticin) g causa conflicto
{g}
{g}
D
Ocurre un conflicto de nombres si una clase hereda dos caractersticas diferentes, ambas efectivas, con el mismo nombre.
53
{f*}
(c2)
redefine f
{f}
{f}
{f} B
redefine f
C
redefine f
D LEGAL
Solo hay conflicto entre dos efectivas
{f}
LEGAL
Ambas versiones se funden 54 en una nueva
A
redefine f
{f}
Soluciones: rename duplicacin undefined (c1)
{f}
C {f}
D ILEGAL
Viola la Regla del nombre nico
55
Conversin en diferida
Dejar que una de las variantes se imponga sobre las otras Es posible al heredar transformar una rutina efectiva en diferida. class C inherit B undefine f feature ... end B {f+} undefine f C {f*}
Viene despus de rename (se aplica al nombre final) pero antes de redefine.
56
Indefinicin y unin
El mecanismo undefine proporciona la capacidad de unir caractersticas bajo herencia mltiple (no necesariamente repetida). Ejemplo: Se desea que C trate a f y g como una nica caracterstica (requiere semntica y signatura compatibles) {fA} A B {fB}
undefine f
{f}
{g}
rename g as f undefine f
{f}
57
Combinacin de propiedades
Todas las restantes combinaciones son posibles: tomar la caracterstica de A y el nombre de B renombrar f y g y darle un nombre nuevo en C Reemplazar ambas versiones por una nueva (caso (c2))
ambas tienen el mismo nombre final (utilizar rename si no)
{fA} A redefine f
{fB} redefine f
C {fC}
58
{f}
oa:A; ob:B; oc:C; od:D; !!od ob:= od; ob. f oc:= od; oc. f oa:= od oa.f { o }
redefine f
{}
{f} B
rename f as bf
C {f}
rename f as cf
{}
{bf, cf}
No hay conflicto de nombres pero surge un nuevo problema debido a la ligadura dinmica.
59
Una clase, que de un antecesor repetido, hereda dos o ms versiones efectivas diferentes de una caracterstica y no las redefine a ambas, debe entonces incluir a una de las dos en una clusula select
60
A {at, proc}
rename at as at1 rename at as at2
A {f}
rename f as g redefine f select f
B {f, g}
Antes de introducir Precursor era la tcnica usada para que una rutina redefinida pudiese invocar a la rutina original.
63
Ejemplo:
VENTANA
redefine display display is do Precursor dibujar_bordes end
{display}
redefine display display is do Precursor dibujar_menu end
VENTANA_ BORDES
VENTANA_ MENU
redefine display
VENTANA_ BORDES_MENU
Solucin:
{display}
redefine display display is do VENTANA_ Precursor MENU dibujar_menu end redefine display display is do {VENTANA}Precursor dibujar_menu dibujar_bordes 66 end
VENTANA_ BORDES
redefine display
redefine display
VENTANA_ BORDES_MENU
El nivel de granularidad para decidir si compartir o duplicar es la clase Ambigedad se resuelve con calificacin de nombres: C::at1; B::at1 67
//ambiguo
69
Cuando se utilizan clases base virtuales se puede llegar a la misma caracterstica a travs de mas de un camino sin que exista ambigedad.
{f,g,h,k} (virtuales) redefine f
C
redefine h
//B::f()
La versin redefinida domina a la virtual La misma situacin con clases base no virtuales produce 71 ambigedad (implica ms de un objeto).
A B
{int v} V
A {int a} C
void D::f() { v++; //correcto solo hay un v a++; //ambiguo hay dos a }
D {f}
class V {public: int x; int f();}; class B: public virtual V { public: int x; int f();}; class C: public virtual V {}; classD : public B, public C {void g();};
void D::g() { x++; //OK! B::x domina a V::x f(); //OK! B::f() domina a V::f() }
72
Solucin Java: herencia mltiple de interfaces. Java permite que una clase pueda heredar de ms de una INTERFACE Interface es el modo de declarar un tipo formado slo por mtodos abstractos (pblicos) y constantes, permitiendo que se escriba cualquier implementacin para estos mtodos. 74
Interfaces Java
SUPERTIPOS
SUBTIPO
Surgen colisiones de nombre 1) Sobrecarga 2) Comparticin 3) Ilegal (si difieren en el tipo del objeto que retorna)
76
Herencia de interfaces
A diferencia de las clases una interfaz puede heredar de ms de una interfaz Se utiliza herencia mltiple si se quiere que una clase implemente un interfaz y herede de otra clase
W X Z interface W { } interface X extends W { } class Y implements W { } class Z extends Y implements X { } Y X Z interface W { } interface X extends W { } interface Y extends W { } class Z implements X, Y {77 } W Y
Suponiendo que existe la clase Velero Cmo modelaramos un VeleroMotor que debe heredar de Barco y de Velero? 80
VeleroMotor
81
VeleroMotor
Importante:
Es conveniente que el programador Java declare interfaces para las clases que cree, ya que NO EXISTE HERENCIA MULTIPLE.
83
La combinacin de clases, genericidad, herencia, redefinicin, polimorfismo, ligadura dinmica y clases diferidas permite satisfacer:
los principios/ reglas/ criterios de modularidad
84