3 Herencia
3 Herencia
3 Herencia
Entender el mecanismo de abstraccin de la herencia. Distinguir entre los diferentes tipos de herencia Saber implementar jerarquas de herencia en C++ Saber discernir entre jerarquas de herencia seguras (bien definidas) e inseguras. Reutilizacin de cdigo: Ser capaz de decidir cundo usar herencia y cundo optar por composicin.
No persist.
Asociacin Todo-Parte
C1
C2
Uso (depend) C1 C2
Agregacin Composicin
Entre clases
Generalizacin
vehiculo areo
avion
helicoptero
HERENCIA Motivacin
Florista cobrar() darRecibo() Panadero cobrar() darRecibo() Vendedor coches
....
cobrar() darRecibo()
HERENCIA Definicin
La herencia es el mecanismo de implementacin mediante el cual elementos ms especficos incorporan la estructura y comportamiento de elementos ms generales (Rumbaugh 99)
Gracias a la herencia es posible especializar o extender la funcionalidad de una clase, derivando de ella nuevas clases. La herencia es siempre transitiva: una clase puede heredar caractersticas de superclases que se encuentran muchos niveles ms arriba en la jerarqua de herencia.
Ejemplo: si la clase Perro es una subclase de la clase Mamfero, y la clase Mamfero es una subclase de la clase Animal, entonces el Perro heredar atributos tanto de Mamfero como de Animal.
La clase A se debe relacionar mediante herencia con la clase B si A ES-UN B. Si la frase suena bien, entonces la situacin de herencia es la ms probable para ese caso
Un pjaro es un animal Un gato es un mamfero Un pastel de manzana es un pastel Una matriz de enteros es un matriz Un coche es un vehculo
Sin embargo, si la frase suena rara por una razn u otra, es muy probable que la relacin de herencia no sea lo ms adecuado. Veamos unos ejemplos:
Un pjaro es un mamfero Un pastel de manzana es una manzana Una matriz de enteros es un entero Un motor es un vehculo
De todas formas, puede haber casos en los que este test puede fallar y sin embargo la relacin de herencia es evidente. Sin embargo, para la mayor parte de los casos, la aplicacin de esta tcnica es adecuada.
La herencia como reutilizacin de cdigo: Una clase derivada puede heredar comportamiento de una clase base, por tanto, el cdigo no necesita volver a ser escrito para la derivada. La herencia como reutilizacin de conceptos: Esto ocurre cuando una clase derivada sobrescribe el comportamiento definido por la clase base. Aunque no se comparte ese cdigo entre ambas clases, ambas comparten el prototipo del mtodo (comparten el concepto).
Clasificacin y generalizacin
La herencia consigue clasificar los tipos de datos (abstracciones) por variedad, acercando un poco ms el mundo de la programacin al modo de razonar humano.
Este modo de razonar humano se denomina GENERALIZACIN, y da lugar a jerarquas de generalizacin/especializacin. La implementacin de estas jerarquas en un lenguaje de programacin da lugar a jerarquas de herencia.
La generalizacin es una relacin semntica entre clases, que determina que la interfaz de la subclase debe incluir todas las propiedades pblicas y privadas de la superclase. Disminuye el nmero de relaciones (asociaciones y agregaciones) del modelo Aumenta la comprensibilidad, expresividad y abstraccin de los sistemas modelados. Todo esto a costa de un mayor nmero de clases
11
Tipos de Herencia
Simple/Mltiple De implementacin/de interfaz A nivel semntico, Bertrand Meyer distingue 17 tipos de herencia.
12
Tipos de Herencia
Simple/Mltiple
13
Tipos de Herencia
De implementacin/de interfaz
De implementacin: La implementacin de los mtodos es heredada. Puede sobreescribirse en las clases hijas. De interfaz: Slo se hereda la interfaz, no hay implementacin a nivel de padre (interfaces en Java, clases abstractas en C++)
14
Herencia
Solapada/Disjunta
Determina si un objeto puede ser a la vez instancia de dos o ms subclases de ese nivel de herencia. C++ no soporta la herencia solapada (tipado fuerte) Determina si todas las instancias de la clase padre son a la vez instancias de alguna de las clases hijas (completa) o, por el contrario, hay objetos de la clase padre que no pertenecen a ninguna subcategora de las reflejadas por las clases hijas (incompleta). A nivel de implementacin, una jerarqua de herencia completa suele implicar que la clase padre puede ser definida como abstracta (es decir, impedir que se creen instancias de ella). Determina si un determinado objeto puede pasar de ser instancia de una clase hija a otra dentro de un mismo nivel de la jerarqua de herencia. C++ no soporta la herencia dinmica (tipado fuerte)
Completa/Incompleta
Esttica/Dinmica
16
Herencia
Caracterizacin: ejemplos
17
HERENCIA
Herencia Simple
Herencia en C++
Visibilidad atributos/mtodos C++ introduce un nuevo mbito de visibilidad para el tratamiento de la herencia: protected
Los datos/funciones miembros protected son privados para todas aquellas clases no derivadas y mtodos externos, pero accesibles para una clase derivada de la clase en que se ha definido la variable protegida.
int main () { Circulo c; c.colorRelleno=NINGUNO; // ERROR! colorRelleno // es privado aqu }
class Figura2D {
...
protected: Color colorRelleno;
...
};
class Circulo : Figura2D { public: void vaciarCirculo() { colorRelleno=NINGUNO; //OK, protected } ... };
20
Herencia Protegida
class Circulo : protected Figura2D { ... };
<<protected>>
Herencia Privada
class Circulo : private Figura2D { ... };
<<private>>
21
Padre
<<??>>
+inicializaTodoAUno()
<<public>>
Hija
Implementa el mtodo Hija::inicializaTodoAUno() suponiendo que la herencia entre Abuela y Padre es: Pblica Protegida Privada
+inicializaTodoAUno()
23
Herencia Simple
AADIR nuevos mtodos/atributos propios de la clase derivada Modificar los mtodos heredados de la clase base REFINAR: se aade comportamiento nuevo antes y/o despus del comportamiento heredado. (Simula, Beta) (se puede simular en C++, Java) C++, Java: Constructores y destructores se refinan REEMPLAZAR: el mtodo heredado se redefine completamente, de forma que sustituye al original de la clase base.
25
Siempre son definidos para las clases derivadas Creacin de un objeto de clase derivada: Se invoca a todos los constructores de la jerarqua Orden de ejecucin de constructores: Primero se ejecuta el constructor de la clase base y luego el de la derivada.
26
Esto implica que la clase derivada aplica una poltica de refinamiento: aadir comportamiento al constructor del padre. Ejecucin implcita del constructor por defecto de clase base al invocar a un constructor de clase derivada. Ejecucin explcita de cualquier otro tipo de constructor en la zona de inicializacin (refinamiento explcito). En particular, el constructor de copia.
(CONSEJO: Inicializacin de atributos de la clase base: en la clase base, no en la derivada)
27
El destructor no se hereda.
Siempre es definido para la clase derivada Destruccin de un objeto de clase derivada: se invoca a todos los destructores de la jerarqua Primero se destruye el objeto derivado y luego el objeto base. Llamada implcita a los destructor de la clase base.
28
Construccion/destruccin en resumen
29
+ TCuenta() + TCuenta(TCuenta &) + operator=() + ~TCuenta() + getTitular() + getSaldo() + getInteres() + setSaldo() + setInteres() + abonarInteresMensual() + mostrar() <<friend>> operator<<()
30
33
TCuentaJoven
- int edad + + + + + + + + TCuentaJoven() TCuentaJoven(const TCuentaJoven&) ~TCuentaJoven() operator=(const TCuentaJoven&) : TCuenta& abonarInteresMensual() : void getEdad() : int setEdad(int) : void mostrar() : void
34
36
Mtodos aadidos
void mostrar(){ TCuenta::mostrar(); Mtodo cout<<Edad:<<edad<<endl; Refinado } friend ostream& operator<< (ostream& os, TCuentaJoven& c){ os << Titular="<<c.titular<<endl; os << "Saldo="<<c.saldo<<endl; os << "Edad="<<c.edad<<endl; os << NumCuentas="<<TCuentaJoven::numCuentas<<endl; return os; } };//fin clase TCuentaJoven
Cmo podrais definir el operador << para que fuese inmune a los cambios en la clase base y adems ocupase menos lneas de cdigo? Qu est ocurriendo con el nmero de cuentas? Hace falta incrementar el numCuentas?
37
Ejercicio: TCuentaEmpresarial
TCuenta
TCuentaEmpresarial TCuentaJoven
- nomEmpresa: char*
Cmo se definira una clase TCuenta Empresarial, que tambin heredara de TCuenta?
+ TCuentaEmpresarial() + TCuentaEmpresarial(TCuentaEmpresarial&) + ~TCuentaEmpresarial() + abonarInteresMensual():void + getNomEmpresa(): char* + mostrar():void <<friend>> operator<< (ostream&,...)
39
Particularidades Herencia
Como ya hemos visto, en las jerarquas de herencia hay un refinamiento implcito de:
Las variables estticas definidas en la clase base tambin son compartidas (heredadas) por las clases derivadas. El operador de asignacin (Tema 4) tampoco se mantiene como mtodo fundacional (es decir, reutilizable sin cambios) en la jerarqua, sino que se sustituye siempre por uno propio de la clase derivada (puede ser de oficio, proporcionado por el compilador). De ah que la forma cannica de la clase implique siempre definir estas cuatro funciones miembro Se heredan las funciones amigas?
40
Ejercicio Propuesto
Definid una jerarqua de herencia en la que se contemplen los empleados de una empresa, almacenando su nombre y su sueldo, y los gerentes como un tipo especial de empleados de los que almacenaremos el departamento y el nombre de su secretaria. Realizar la especificacin UML y el .h de las clases implicadas.
41
HERENCIA
Herencia Mltiple
44
TCuenta
TEmpresa
TCuentaEmpresarial
Clase Madre1
Clase Madre2
46
47
HERENCIA
Herencia de Interfaz
Herencia de interfaz
La herencia de interfaz NO hereda cdigo Es una herencia sin efectos secundarios. Se utiliza exclusivamente con el propsito de garantizar la sustituibilidad.
50
El principio de sustitucin
Debe ser posible utilizar cualquier objeto instancia de una subclase en el lugar de cualquier objeto instancia de su superclase sin que la semntica del programa escrito en los trminos de la superclase se vea afectado. (Liskov, 1987)
Subtipo: Una clase B, subclase de A, es un subtipo de A si podemos sustituir instancias de A por instancias de B en cualquier situacin y sin ningn efecto observable.
POO 2007-2008
El principio de sustitucin
Caracterizan los objetos por su clase Caracterizan los objetos por su comportamiento
Lenguaje debilmente tipado: funcion medir(objeto) { si (objeto <= 5) sino si (objeto == 0) ...}
POO 2007-2008
El principio de sustitucin
Java: directamente
class Dependiente { public: int cobrar(); void darRecibo(); ...}; class Panadero : public Dependiente {...}
class Dependiente { public int cobrar(); public void darRecibo(); ...}; class Panadero extends Dependiente {...} Panadero p = new Panadero(); Dependiente d1=p; // sustit.
Panadero p; Dependiente& d1=p; // sustit. Dependiente* d2=&p; // sustit. 2007-2008 POO Dependiente d3=p; // NO sustit.
HERENCIA DE INTERFAZ
Objetivos:
POO 2007-2008
HERENCIA DE INTERFAZ
Clases abstractas
Son clases en las que alguno de sus mtodos no est definido (mtodos abstractos) No se pueden crear objetos de estas clases. S se pueden crear referencias (o punteros) a objeto de una clase abstracta (que apuntarn a objetos de clases derivadas)
Propsito: Garantizar que las clases derivadas proporcionan una implementacin propia de ciertos mtodos. Sustituibilidad: Se garantiza la sustituibilidad.
POO 2007-2008
HERENCIA DE INTERFAZ
Clases abstractas
Las clases que deriven de clases abstractas (o interfaces) deben implementar todos los mtodos abstractos (o sern a su vez abstractas). La clase derivada implementa el interfaz de la clase abstracta.
POO 2007-2008
HERENCIA DE INTERFAZ
Notacin UML para clases abstractas
Vehculo
CLASE ABSTRACTA
CLASE ABSTRACTA
Terrestre {abstract}
CLASE ABSTRACTA
Areo
Coche
Bicicleta
Avin
Helicptero
CLASES CONCRETAS
POO 2007-2008
HERENCIA DE INTERFAZ
POO 2007-2008
HERENCIA DE INTERFAZ
abstract class Forma { private int posx, posy; public abstract void dibujar(); public int getPosicionX() { return posx; } ... }
Clase derivada class Circulo extends Forma { private int radio; public void dibujar() {...}; ... }
POO 2007-2008
HERENCIA DE INTERFAZ
Interfaces
Declaracin de un conjunto de mtodos sin definir. En C++, son clases abstractas donde ningn mtodo est definido. Java/C#: declaracin explcita de interfaces
HERENCIA DE INTERFAZ
Notacin UML para interfaces
<<interface>>
Vehculo
INTERFAZ
CLASE ABSTRACTA
Terrestre {abstract}
CLASE ABSTRACTA
Areo
Coche
Bicicleta
Avin
Helicptero
CLASES CONCRETAS
POO 2007-2008
HERENCIA DE INTERFAZ
Interfaces en Java
interface Forma { // - Sin atributos de instancia // - Slo constantes estticas // - Todos los mtodos son abstractos void dibujar(); int getPosicionX(); ... } class Circulo implements Forma { private int posx, posy; private int radio; public void dibujar() {...}; public int getPosicionX() {...}; POO 2007-2008 }
HERENCIA DE INTERFAZ
Interfaces en C++
class Forma { // - Sin atributos de instancia // - Slo constantes estticas // - Todos los mtodos son abstractos void dibujar()=0; int getPosicionX()=0; // resto de mtodos virtuales puros... } class Circulo : public Forma // Herencia pblica { private: int posx, posy; int radio; public: void dibujar() {...} int getPosicionX() {...}; POO 2007-2008 }
HERENCIA DE INTERFAZ
compareTo(Comparable) : int
HERENCIA DE INTERFAZ
+ TCuentaVirtual() + TCuentaVirtual(TCuentaVirtual) + TCuentaJoven() + ~TCuenta() + TCuentaJoven(TCuentaJoven) + getNombre() const + ~TCuentaJoven() + getSaldo() const + getEdad(): int + getInteres() const + setEdad(int): void + setSaldo() +abonarInteresMensual(): void + setInteres() +mostrar() +abonarInteresMensual(): void <<friend>> operator<<() +mostrar() <<friend>> operator<<() POO 2007-2008
HERENCIA DE INTERFAZ
class TCuentaVirtual { protected: ... public: ... virtual void abonarInteresMensual()=0; }; class TCuentaJoven: public TCuentaVirtual{ private: int edad; public: ... // IMPLEMENTACION void abonarInteresMensual(){ //no inters si el saldo es inferior al lmite if (getSaldo()>=10000){ setSaldo(getSaldo()*(1+getInteres()/12/100)); } }; POO 2007-2008 // sigue...
HERENCIA DE INTERFAZ
// sigue... void mostrar(){ TCuentaVirtual::mostrar(); cout<<"Edad:"<<edad<<endl; } friend ostream& operator<<(ostream& os, TCuentaJoven& c){ // os<<(TCuentaVirtual)c<<endl; // ERROR: cast a clase abstracta c.TCuentaVirtual::mostrar(); // Problema: mostrar() usa cout os << "Edad="<<unaCuenta.edad<<endl; return os; }
(Encuentra el modo de reutilizar el cdigo del operador de salida de la clase TCuentaVirtual POO en el operador de salida de TCuentaJoven) 2007-2008
La clase derivada redefine el comportamiento de la clase base Se pretende invocar a ciertos mtodos redefinidos desde referencias a objetos de la clase base (principio de sustitucin).
En C++ es necesario indicar explcitamente que dicha sustitucin es posible mediante la definicin de dichos mtodos como virtuales (mediante la palabra clave virtual). En muchos lenguajes OO este rasgo es soportado de forma natural: Por ejemplo, en Java, los mtodos son virtuales por defecto. Sobreescritura: redefinicin de mtodos virtuales en clases derivadas. POO 2007-2008
Si una clase tiene mtodos virtuales Es posible utilizar el principio de sustitucin: Heredar de ella y sobreescribir los mtodos virtuales El destructor de esta clase base debe declararse como mtodo virtual.
POO 2007-2008
TComisionista double base, comisin, ventas; + TComisionista() + TComisionista(TComisionista &) + ~TComisionista() + setComisin() + getComisin() const + setBase() + getBase() const
POO 2007-2008
int main(){ int tipo; Empleado *eptr; cout<<Introduce tipo<<endl; cin>>tipo; //1:fijo, 2 comisionista switch (tipo){ case 1: eptr=new Fijo(); break; case 2:eptr=new Comisionista(); break; } eptr->getSalario(); delete eptr; }
POO 2007-2008
HERENCIA
Herencia de Implementacin
Herencia de implementacin
Habilidad para que una clase herede parte o toda su implementacin de otra clase. Debe ser utilizada con cuidado.
72
En la herencia existe una tensin entre expansin (adicin de mtodos ms especficos) y contraccin (especializacin o restriccin de la clase padre) Esta tensin est en la base de su poder, y tambin de los problemas asociados con su uso. En general, la redefinicin de mtodos slo debera usarse para hacer las propiedades ms especficas
73
Especializacin
La clase derivada es una especializacin de la clase base: aade comportamiento pero no modifica nada
VentanaDeTexto editar()
74
Especificacin
Implementa mtodos no definidos en la clase base (mtodos abstractos o diferidos). No aade ni elimina nada. La clase derivada es una realizacin (o implementacin) de la clase base.
Pila {abstract} apila(Object) : void desapila() : Object tope() : Object
PilaDeEnteros
apila(Object) : void desapila() : Object tope() : Object
75
Restriccin (limitacin)
Pjaro Volar()
No todo lo de la clase base sirve a la derivada. Hay que redefinir ciertos mtodos para eliminar comportamiento presente en la clase base
Pingino Nadar()
Generalizacin
Ventana Coordenada_x Coordenada_y Mover()
Se extiende el comportamiento de la clase base para obtener un tipo de objeto ms general. Usual cuando no se puede modificar la clase base. Mejor invertir la jerarqua.
77
La implementacin se parece pero semnticamente los conceptos no estn relacionados jerrquicamente (test es-un). INCORRECTA!!!!
78
Herencia de Construccin
Una clase hereda pate de su funcionalidad de otra, modificando el interfaz heredado La clase derivada no es una especializacin de la clase base (puede que incluso no haya relacin esun)
No se cumple el principio de sustitucin (ni se pretende) P. ej., una Pila puede construirse a partir de un Array
Array elementoAt(int i) : Object capacidad() : int numElementos() : int
Pila
apila(Object) : void desapila() : Object tope() : Object
79
La herencia privada en C++ implementa un tipo de herencia de construccin que s preserva el principio de sustitucin: tambin conocida como Herencia de Implementacin Pura
El hecho de que Pila herede de Array no es visible para el cdigo que usa la pila.
Pila
<<private>> apila(Object) : void desapila() : Object tope() : Object
80
HERENCIA
Beneficios y costes de la herencia
Beneficios de la Herencia
Reusabilidad software Comparticin de cdigo Consistencia de interface Construccin de componentes Prototipado rpido Polimorfismo Ocultacin de informacin
[BUDD] 8.8
82
Costes de la Herencia
Velocidad de ejecucin Tamao del programa Sobrecarga de paso de mensajes Complejidad del programa
[BUDD] 8.9
83
HERENCIA
Eleccin de tcnica de reuso
Herencia vs Todo-Parte
Herencia es una relacin entre clases, mientras que Agregacin/Composicin es una relacin entre objetos
Herencia es menos flexible Donde se detecta una relacin HAS-A no siempre es posible cambiarla por una relacin de herencia. Sin embargo, donde se detecta una relacin de herencia, siempre es posible reformularla para que se convierta en una relacin de composicin.
Un programador de C++ es un programador Todo programador de C++ tiene un programador en su interior Todo programador de C++ tiene una vocacin de programar en su interior
Regla del cambio: no se debe usar herencia para describir una relacin IS-A si se prev que los componentes puedan cambiar en tiempo de ejecucin (si preveo que pueda cambiar mi vocacin ).
Las relaciones de composicin se establecen entre objetos, y por tanto permiten un cambio ms sencillo del programa.
Regla del polimorfismo: la herencia es apropiada para describir una relacin IS-A cuando las entidades o los componentes de las estructuras de datos del tipo ms general pueden necesitar relacionarse con objetos del tipo ms especializado (e.g. por reuso).
85
Herencia (IS-A) y Composicin (HAS-A) son los dos mecanismos ms comunes de reuso de software
class coche {... private: Motor m; }; HERENCIA: Relacin ser-un: ENTRE CLASES
Ejemplo: construccin del tipo de dato Conjunto a partir de una clase preexistente Lista
class Lista{
public: Lista(); //constructor void add (int el); int firstElement(); int size(); int includes(int el); void remove (int pos);
};
Queremos que la nueva clase Conjunto nos permita aadir un valor al conjunto, determinar el nmero de elementos del conjunto y determinar si un valor especfico se encuentra en el conjunto.
87
Un objeto es una encapsulacin de datos y comportamiento. Por tanto, si utilizamos la Composicin estamos diciendo que parte del estado de la nueva estructura de datos es una instancia de una estructura existente
class Conjunto{ public: //constructor debe inicializar el objeto Lista Conjunto():losDatos(){}; int size(){return losDatos.size();}; int includes (int el){return losDatos.includes(el);}; //un conjunto no puede contener valor ms de una vez void add (int el){ if (!includes(el)) losDatos.add(el); }; private: Lista losDatos; };
88
La composicin proporciona un mecanismo para reutilizar un componente software existente en la creacin de una nueva aplicacin, simplificando su implementacin La composicin no realiza ninguna asuncin respecto a la sustituibilidad. Cuando se forma de esta manera, un Conjunto y una Lista son tipos de datos totalmente distintos, y se supone que ninguno de ellos puede sustituir al otro en ninguna situacin. La composicin se puede aplicar del mismo modo en cualquier lenguaje OO e incluso en lenguajes no OO.
89
Con herencia una clase nueva puede ser declarada como una subclase de una clase existente, lo que provoca que todas las reas de datos y funciones asociadas con la clase original se asocien automticamente con la nueva abstraccin de datos.
class Conjunto : public Lista{ public: Conjunto() : Lista() {}; //un conjunto no puede contener valor ms de una vez void add (int el){ //refinamiento if (!includes(el)) Lista::add(el); }; };
Implementamos en trminos de clase base (no objeto) No existe una lista como dato privado Las operaciones que actan igual en la clase base y en la derivada no deben ser redefinidas (con composicin s).
90
As, las instancias de la nueva abstraccin deberan comportarse de manera similar a las instancias de la clase padre.
91
Define ms claramente la interfaz que soporta el nuevo tipo, independientemente de la interfaz del objeto parte. Problema del yo-yo: En la herencia las operaciones de la clase hija son un superconjunto de las de la clase padre, por lo que el programador debe examinar todas las clases en la jerarqua para conocer qu operaciones son legales para la nueva estructura.
La composicin slo presupone que el tipo de datos X se utiliza para IMPLEMENTAR la clase C. Es fcil por tanto:
Dejar sin implementar los mtodos que, siendo relevantes para X, no lo son para la nueva clase C Reimplementar C utilizando un tipo de datos X distinto sin impacto para los usuarios de la clase C.
92
Requiere menos cdigo. Oferta ms funcionalidad: cualquier nuevo mtodo asociado al padre estar inmediatamente disponible para todos sus hijos
Soporta directamente el principio de sustitucin (composicin no) La herencia es ligeramente ms eficiente que la composicin (evita una llamada). Los usuarios pueden manipular la nueva estructura mediante mtodos de la clase base, incluso si stos no son apropiados. Cambiar la base de una clase puede causar muchos problemas a los usuarios de dicha clase.
93
Desventajas
Herencia: un empleado es una persona. Composicin: una persona tiene un domicilio Composicin: una lista tiene un puntero de tipo nodo al nodo que est en cabeza de la lista (tener-un).
Herencia entre empleado y jefe: Un jefe es un empleado Composicin entre empresa y empleado (o empleado y jefe):
Un empresa puede tener una lista de empleados y otra de jefes Por el principio de los subtipos, una empresa puede tener un nica lista donde aparezcan tanto los jefes como empleados.
94
Suponed que tenemos una estructura genrica de documento, y que queremos visualizar instancias de documentos con esa estructura en distintos formatos (HTML, PDF, DOC, etc.).
95
sera posible modificar el modo de visualizacin del documento? Con cul se cumplira el dicho Una HTML vez documento HTML, siempre documento web?
PDF DOC
96
Eleccin de tcnica de reuso Ejercicio: Videoclub Videoclub: Un videoclub dispone de una serie de pelculas que pueden estar en DVD o en VHS (una sola cinta por pelcula). De las pelculas interesa guardar el ttulo, el autor, el ao de edicin y el idioma (o los idiomas, en caso de DVD). El precio de alquiler de las pelculas vara en funcin del tipo de pelcula. Qu clases implementarais y cmo las relacionarais?
97
Mediante herencia:
Pelcula
DVD
VHS
Cambiar de VHS a DVD supondra eliminar la instancia de pelcula y volverla a crear (la herencia es una relacin inmutable entre clases). Donde trabajaba con instancia de VHS (e.g. visualizar) ahora tengo que trabajar con instancias de DVD.
98
Mediante composicin:
Pelcula
1..1 0..1
DVD
1..1 0..1
VHS
Ms flexible, ya que composicin implica una relacin a nivel de objeto (no de clase). Cmo indico que tengo que tener un DVD o un VHS?
99
DVD
VHS
Ahora si yo renuevo mi parque de pelculas y cambio las VHS por DVD no hay ningn problema, puesto que puedo trabajar con instancias de soporte (e.g. visualizar), y ambos son subtipos de soporte. Se aprovechan las caractersticas de la herencia, y se aade flexibilidad.
100
Eleccin de tcnica de reuso Ejercicio: Videoclub con varias copias Qu cambios habra que realizar en una y otra solucin si el crecimiento de mi videoclub aconsejara tener varias copias de una misma pelcula?
101
1..1 0..n
DVD
1..1 0..n
VHS
Pelcula
DVD
102
HERENCIA
EJERCICIOS
Dibujad un diagrama de clases que muestre las dos categoras que existen de Clientes de una empresa: Clientes externos, que son otras compaas, y Clientes internos, que son todas las divisiones de dentro de la empresa. Suponed ahora que Divisin (cuyas instancias son las distintas divisiones de la empresa) es una clase del sistema. Cambiara en algo vuestra solucin?
105
Divisiones Interno
Cliente Externo
106
Dibujad un diagrama de clases que muestre la estructura de un captulo de libro; un captulo est compuesto por varias secciones, cada una de las cuales comprende varios prrafos y figuras. Un prrafo incluye varias sentencias, cada una de las cuales contiene varias palabras.
Suponed que en un futuro se prev que el sistema gestione adems de prrafos y figuras otros componentes, como tablas, listas, vietas, etc. Suponed adems que una palabra puede aparecer en varias sentencias.
107
Captulo
0..N {ordered}
Seccin
0..N {ordered}
Prrafo
0..N {ordered}
Sentencia
0..N 0..N {ordered}
Palabra
108
Se desea desarrollar un sistema de nmina para los trabajadores de una empresa. Los datos personales de los trabajadores son Nombre y Apellidos, Direccin, DNI. Existen diferentes tipos de trabajadores: Fijos Mensuales: que cobran una cantidad fija al mes Comisionistas: cobran un porcentaje fijo por las ventas que han realizado Por Horas: cobran un precio por cada una de las horas que han realizado durante el mes. El precio es fijo para las primeras 40 horas y es otro para las horas realizadas a partir de la 40 hora mensual. Jefe: cobra un sueldo fijo (no hay que calcularlo) Cada empleado tiene obligatoriamente un jefe (exceptuando los jefes que no tienen ninguno). El programa debe permitir dar de alta trabajadores, fijar sus emolumentos, horas o ventas realizadas e imprimir la nmina correspondiente al final de mes.
109
PorHoras Comisionista FijoMensual sueldo New Destroy modificarSueldo comisin% ventas New Destroy modificarComisin modificarVentas precioHora precioHoraExtra horas New Destroy modificarPrecioHora modificarPrecioHorasExtras modificarHoras
110
Resumen
Una de las claves del poder de la programacin orientada a objetos es lograr la reutilizacin del software a travs de la herencia. El programador puede designar que la nueva clase herede los datos miembro y funciones miembro de una clase base definida previamente. En este caso, la clase nueva se conoce como clase derivada. En la herencia simple, una clase se deriva a partir de una sola clase base. En la herencia mltiple, una clase derivada hereda de varias clases base (que posiblemente no tengan relacin entre ellas). Una clase derivada por lo general agrega sus propios datos miembro y funciones miembro, por lo que comnmente tiene una definicin mayor que su clase base. Una clase derivada es ms especfica que su clase base y por lo general representa menos objetos. Una clase derivada no puede acceder a los datos miembro private de su clase base; permitirlo violara el encapsulamiento de la clase base. Sin embargo, una clase derivada puede acceder a los datos miembro public y protected de su clase base. Un constructor de clase derivada siempre llama primero al constructor de su clase base, para que cree e inicialice los miembros de clase base de la clase derivada.
111
Resumen
Los destructores se invocan en el orden inverso al de las llamadas de constructor, por lo que el destructor de la clase derivada se invoca antes que el destructor de su clase base. La herencia permite la reutilizacin del software, la cual ahorra tiempo en el desarrollo y promueve el empleo de software de alta calidad previamente probado y depurado. La herencia se puede hacer a partir de bibliotecas de clases ya existentes. Algn da, la mayor parte del software se construir a partir de componentes reutilizables estandarizados, de la misma manera que se construye la mayor parte del hardware. El implementador de una clase derivada no necesita acceder al cdigo fuente de su clase base, pero s necesita interactuar con la clase base y el cdigo objeto de la clase base. Un objeto de una clase derivada puede ser tratado como objeto de su clase base pblica correspondiente. Sin embargo, lo opuesto no es cierto. Una clase base existe en una relacin jerrquica con sus clases derivadas simples.
112
Resumen
Una clase puede existir por s sola. Cuando se utiliza dicha clase con el mecanismo de herencia, se vuelve una clase base que suministra atributos y comportamientos a otras clases o se vuelve una clase derivada que hereda esos atributos y comportamientos. Las jerarquas de herencia pueden tener una profundidad arbitraria dentro de las limitaciones fsicas de su sistema particular. Las jerarquas son herramientas tiles para entender y administrar la complejidad. Ahora que el software se vuelve cada vez ms complejo, C++ ofrece mecanismos para manejar estructuras jerrquicas mediante herencia y polimorfismo. Es posible utilizar una conversin mediante cast explcita para convertir un apuntador de clase base en apuntador de clase derivada. Tal apuntador no se debe desreferenciar, a menos que en realidad apunte a un objeto del tipo de la clase derivada. El acceso protected sirve como nivel intermedio de proteccin entre el acceso public y el acceso private. Los miembros y friend de la clase base y los miembros y friend de las clases derivadas pueden acceder los miembros protected de una clase base; ninguna otra funcin puede acceder a los miembros protected de una clase base.
113
Resumen
Los miembros protected se utilizan para extender los privilegios a las clases derivadas, negando dichos privilegios a las funciones que no son de la clase ni son friend. La herencia mltiple se indica poniendo dos puntos (:) a continuacin del nombre de la clase derivada y luego una lista separada por comas de clases base. Para llamar a los constructores de la clase base, se emplea sintaxis de inicializador de miembros en el constructor de la clase derivada. Cuando se deriva una clase a partir de una clase base, sta se puede declarar como public, protected o private. Cuando se deriva una clase a partir de una clase base public, los miembros public de sta se vuelven miembros public de la clase derivada y los miembros protected de la clase base se vuelven miembros protected de la clase derivada. Cuando se deriva una clase a partir de una clase base protected, los miembros public y protected de sta se vuelven miembros protected de la clase derivada. Cuando se deriva una clase a partir de una clase base private, los miembros public y protected de sta se vuelven miembros private de la clase derivada.
114
Resumen
Una clase base puede ser una clase base directa o indirecta de una clase derivada. Una clase base directa es aqulla que se lista explcitamente cuando se declara la clase derivada. Una clase base indirecta no se lista explcitamente; en cambio, se hereda de varios niveles ms arriba en el rbol jerrquico. Cuando un miembro de la clase base es inadecuado para una clase derivada, simplemente se redefine dicho miembro en la clase derivada. Es importante distinguir entre las relaciones "es un" y "tiene un". En las relaciones "tiene un", un objeto de clase tiene como miembro un objeto de otra clase. En las relaciones "es un", un objeto de un tipo de clase derivada tambin puede ser tratado como objeto del tipo de la clase base. "Es un" significa herencia. "Tiene un" significa composicin. Es posible asignar un objeto de clase derivada a un objeto de clase base. Este tipo de asignacin tiene sentido, pues la clase derivada tiene miembros que corresponden a cada uno de los miembros de la clase base. Es posible convertir implcitamente un apuntador a un objeto de clase derivada en apuntador a un objeto de clase base.
115
Resumen
Es posible convertir un apuntador de clase base en apuntador de clase derivada mediante una conversin cast explcita. El destino debe ser un objeto de clase derivada. Una clase base especifica comunidad. Todas las clases derivadas de una clase base heredan las capacidades de sta. En el proceso de diseo orientado a objetos, el diseador busca la comunidad y la factoriza para formar clases base deseables. Despus las clases derivadas se personalizan ms all de las capacidades heredadas de la clase base. La lectura de un conjunto de declaraciones de clase derivada puede ser confusa, pues no todos los miembros de la clase derivada estn presentes en dichas declaraciones. En particular, los miembros heredados no se listan en las declaraciones de las clases derivadas, pero estos miembros de hecho estn presentes en las clases derivadas. Las relaciones "tiene un" son ejemplos de la creacin de clases nuevas por medio de composicin de clases ya existentes. Las relaciones "conoce un" son ejemplos de objetos que contienen apuntadores o referencias a otros objetos, por lo que estn conscientes de ellos.
116
Resumen
Los constructores de objetos miembro se invocan en el orden en que se declaran los objetos. En la herencia, los constructores de clase base se invocan en el orden en que se especifica la herencia y antes del constructor de la clase derivada. En el caso de un objeto de clase derivada, primero se invoca al constructor de la clase base y luego al de la clase derivada (que puede llamar a constructores de objetos miembro). Cuando se destruye el objeto de la clase derivada, se invocan los destructores en el orden inverso al de los constructores: primero se llama al destructor de la clase derivada, luego al de la clase base. Es posible derivar una clase a partir de ms de una clase base; tal derivacin se llama herencia mltiple. La herencia mltiple se indica poniendo a continuacin del carcter de dos puntos (:), que indica herencia, una lista separada por comas de clases base. El constructor de la clase derivada llama a los constructores de las distintas clases base por medio de la sintaxis de inicializador de miembros. Los constructores de clases base se invocan en el orden en que se declaran las clases base durante la herencia.
117