You are on page 1of 100

Programacin orientada a objetos

TEMA 3 HERENCIA
Cristina Cachero, Pedro J. Ponce de Len
versin 3 (Curso 10/11) (3 sesiones)

POO

Tema 3. HERENCIA Objetivos


!

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.

Herencia Del tema anterior


Persistente Entre objetos
"

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()

Asociamos ese comportamiento a una categora general (generalizacin)

CLASE DERIVADA (C++) CLASE HIJA SUBCLASE

Dependiente cobrar() darRecibo()


CLASE BASE (C++) CLASE PADRE SUPERCLASE
4

Clasificacin y generalizacin
!

La mente humana clasifica los conceptos de acuerdo a dos dimensiones:


! !

Pertenencia (TIENE-UN) -> Relaciones todo-parte Variedad (ES-UN) -> Herencia

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.

Herencia como implementacin de la Generalizacin


!

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
7

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.

HERENCIA Test ES-UN


!

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

HERENCIA Test ES-UN


!

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

10

HERENCIA Principales usos


!

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. ! Herencia de implementacin 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). ! Herencia de interfaz
11

Tipos de Herencia
!

Simple/Mltiple De implementacin/de interfaz

12

Tipos de Herencia
!

Simple/Mltiple
!

Simple: nica clase base

Mltiple: Ms de una clase base

13

Tipos de Herencia
!

De implementacin/de interfaz
!

De implementacin: La implementacin de los mtodos es heredada. Puede sobreescribirse en las clases derivadas. De interfaz: Slo se hereda la interfaz, no hay implementacin a nivel de clase base (interfaces en Java, clases abstractas en C++)

14

Herencia
!

Caracterizacin semntica Atributos de la generalizacin


!

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). 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 DE IMPLEMENTACIN
Herencia Simple

Herencia Simple en C++


" Mediante la herencia, las propiedades definidas en una clase base son heredadas por la clase derivada. " La clase derivada puede aadir propiedades especficas (atributos, mtodos o roles)

19

Herencia Simple en C++


class Figura2D { public: ... void setColor(Color c); Color getColor() const; private: Color colorRelleno; ... }; class Circulo : Figura2D { ... public: void vaciarCirculo() { colorRelleno=NINGUNO; // ERROR! colorRelleno es privado setColor(NINGUNO); // OK } };

La parte privada de una clase base no es directamente accesible desde la clase derivada.

int main() { Circulo c; c.setColor(AZUL); c.getColor(); c.vaciarCirculo(); ... }


20

Herencia en C++
!
!

Visibilidad atributos/mtodos mbito de visibilidad protected


Los datos/funciones miembros protected son directamente accesibles desde la propia clase y sus clases derivadas. Tienen visibilidad privada para el resto de mbitos. En UML, se especifica con #.
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 } ... };
21

Tipos de Herencia Simple (en C++)


!

Herencia Pblica (por defecto)


class Circulo : public Figura2D { ... };
<<public>>

Herencia Protegida
class Circulo : protected Figura2D { ... };
<<protected>>

Herencia Privada
class Circulo : private Figura2D { ... };
<<private>>

22

Tipos de Herencia Simple


mbito Herencia Visibilidad en clase base

CD (*) H. Pblica No direct. accesible Protected Public

CD H. Protegida No direct. accesible Protected Protected

CD H. privada No direct. accesible Private Private

Private Protected Public

(*) CD: Clase derivada


23

Tipos Herencia Simple Ejercicio


Abuela
+ publico: int # protegido: int - privado: int + setPublicoAbuela(int) + setProtegidoAbuela(int) + setPrivadoAbuela(int) + inicializaTodoAUno();

Padre

<<??>>
+inicializaTodoAUno()

<<public>>
Hija

Implementa el mtodo Hija::inicializaTodoAUno() suponiendo que la herencia entre Abuela y Padre es: Pblica Protegida Privada

+inicializaTodoAUno()
24

Herencia Simple
!

Mtodos en las clases derivadas En la clase derivada se puede:


! !

Aadir nuevos mtodos/atributos propios de la clase derivada Modificar los mtodos heredados de la clase base
!

REFINAMIENTO: 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 REEMPLAZO: el mtodo heredado se redefine completamente, de forma que sustituye al original de la clase base.

26

El constructor en herencia simple


!

Los constructores no se heredan


! !

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.

27

El constructor en herencia simple

A B C

28

El constructor en herencia simple


!

Esto implica que la clase derivada aplica una poltica de refinamiento: aadir comportamiento al constructor de la clase base. 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)

29

El constructor en herencia simple


!

Ejemplo
class Figura2D { Color colorRelleno; public: Figura2D() : colorRelleno(NINGUNO) {} Figura2D(Color c) : colorRelleno(c) {} Figura2D(const Figura2D& f) : colorRelleno(f.colorRelleno) {} ...}; class Circulo : Figura2D { double radio; public: Circulo() : radio(1.0) {} //llamada implcita a Figura2D() Circulo(Color col, double r) : Figura2D(col), radio(r) {} Circulo(const Circulo& cir) : Figura2D(cir), radio(cir.radio) {} ...};
30

El destructor en herencia simple


!

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 ejecuta destructor de la clase derivada y luego el de la clase base. Llamada implcita a los destructor de la clase base.
31

El destructor en herencia simple

A B C

32

Construccion/destruccin en resumen
!

Los objetos se destruyen en orden inverso al de construccin.

33

Ejemplo Clase Base


TCuenta
# # # #
+ + + + + + + + + + +

titular: string saldo: double interes: double numCuentas: int


TCuenta() TCuenta(const TCuenta &) operator=(const Tcuenta &) : TCuenta& ~TCuenta() getTitular() : string getSaldo() : double getInteres() : double setSaldo(double) : void setInteres(double) : void abonarInteresMensual() : void mostrar() : void
34

Herencia Simple (base): TCuenta


class TCuenta{ public: TCuenta(string t, double s=0.0, double i=0.0) : titular(t), saldo(s), interes(i) { numCuentas++; } ... protected: string titular; double saldo; double interes; static int numCuentas; };

35

Herencia Simple (base): TCuenta (II)


TCuenta::TCuenta(const TCuenta& tc) : titular(tc.titular), saldo(tc.saldo), interes(tc.interes) { numCuentas++; } TCuenta& TCuenta::operator=(const TCuenta& tc) { if (this!=&tc) { titular = tc.titular; saldo=tc.saldo; interes=tc.interes; } return*this; } TCuenta::~TCuenta(){ numCuentas--; }

36

Herencia Simple (base): TCuenta (III)


void TCuenta::abonarInteresMensual() { setSaldo(getSaldo()*(1+getInteres()/100/12)); }; void TCuenta::mostrar () { cout << NumCuentas= << TCuenta::numCuentas << endl; cout << Titular= << unaCuenta.titular << endl; cout << Saldo= << unaCuenta.saldo << endl; cout << Interes= << unaCuenta.interes << endl; } }

37

Ejemplo clase derivada


TCuenta

TCuentaJoven
- int edad + + + + + + + + TCuentaJoven() TCuentaJoven(const TCuentaJoven&) ~TCuentaJoven() operator=(const TCuentaJoven&) : TCuenta& abonarInteresMensual() : void getEdad() : int setEdad(int) : void mostrar() : void

(Los mtodos cuya implementacin se hereda de la clase base no se especifican en UML)

38

Herencia Simple (derivada): TCuentaJoven (I)


class TCuentaJoven: public TCuenta { private: Hay que incrementar int edad; numCuentas? public: TCuentaJoven(string unNombre,int unaEdad, double unSaldo=0.0, double unInteres=0.0) : TCuenta(unNombre,unSaldo,unInteres), edad(unaEdad) { } TCuentaJoven(const TCuentaJoven& tcj) // llamada explcita a constructor de copia de TCuenta. : TCuenta(tcj), edad(tcj.edad) { } ~TCuenta() { edad=0; } TCuenta& operator=(const TCuentaJoven& tcj) { if (this!=&tcj) { TCuenta::operator=(tcj); Refinamiento edad = tcj.edad; } return *this; }
39

Herencia Simple (derivada): TCuentaJoven (II)


void abonarInteresMensual() { if (getSaldo()>=10000) { setSaldo(getSaldo()*(1+getInteres()/12/100)); } } int getEdad(){return edad;}; void setEdad(int unaEdad){edad=unaEdad;}; void mostrar(){ TCuenta::mostrar(); cout<<Edad:<<edad<<endl; } };//fin clase TCuentaJoven Mtodo Refinado Mtodos aadidos Reemplazo //no inters si el saldo es inferior al lmite

40

Herencia Simple Upcasting


Convertir un objeto de tipo derivado a tipo base TCuentaJoven tcj; cout << (TCuenta)tcj << endl; cout << TCuenta(tcj) << endl; TCuenta tc; tc = tcj; // upcasting implcito cout << tc << endl;
42

Herencia Simple (derivada): Upcasting


Cuando se convierten objetos en C++, se hace object slicing TCuentaJoven tcj; tcj (TCuenta)tcj TCuenta TCuentaJoven

43

Herencia Simple (derivada): Upcasting


Con punteros o referencias en C++, NO hay object slicing TCuentaJoven* tcj = new TCuentaJoven; TCuenta* tc = tcj; // upcasting tcj
tcj->getEdad(); // OK

TCuenta TCuentaJoven (objeto)

tc
tc->getEdad(); // ERROR POR QU??
44

Particularidades Herencia en C++


!

En las jerarquas de herencia hay un refinamiento implcito de:


! !

Constructor por defecto Destructor

! ! !

El constructor de copia se refina explcitamente. El operador de asignacin se reemplaza. De ah que la forma cannica de la clase implique siempre definir estas cuatro funciones miembro. Las propiedades de clase definidas en la clase base tambin son compartidas (heredadas) por las clases derivadas.
47

HERENCIA DE IMPLEMENTACIN
Herencia Mltiple

Ejemplo Herencia Mltiple


class TEmpresa{ protected: string nomEmpresa; public: TEmpresa(string unaEmpresa) : nomEmpresa(unaEmpresa) {}; void setNombre(string nuevoNombre) { nomEpresa = numvoNombre; } ~TEmpresa() {} }; TCuenta TEmpresa

TCuentaEmpresarial Cmo implementar TCuentaEmpresarial?


50

Ejemplo Herencia Mltiple (II)


class TCuentaEmpresarial : public TCuenta, public TEmpresa { public: TCuentaEmpresarial(string unNombreCuenta, string unNombreEmpresa, double unSaldo=0, double unInteres=0) : TCuenta(unNombreCuenta,unSaldo,unInteres), TEmpresa(unNombreEmpresa) {}; };

51

Problemas en Herencia Mltiple

TCuenta

TEmpresa

(1) Clase Abuela (2)

TCuentaEmpresarial

Clase Madre1

Clase Madre2

Clase Hija Qu problemas pueden darse en (1)? Y en (2)?


52

Colisin de nombres en herencia mltiple


Resolver los nombres mediante mbitos: class TCuentaEmpresarial: public TCuenta, public Tempresa { { string n; if n= TCuenta::getNombre(); else n= TEmpresa::getNombre(); } };
53

Duplicacin de propiedades en herencia mltiple En C++ se resuelve usando herencia virtual:


class Madre_1: virtual public Abuela{ } class Madre_2: virtual public Abuela{ } class Hija: public Madre_1, public Madre_2 { Hija() : Madre_1(), Madre_2(), Abuela(){ }; }
54

HERENCIA DE INTERFAZ

Herencia de interfaz
!

La herencia de interfaz NO hereda cdigo Slo se hereda la interfaz (a veces con una implementacin parcial o por defecto). Se utiliza exclusivamente con el propsito de garantizar la sustituibilidad.

57

Herencia de interfaz

A* obj =

new B();

obj->x(); // OK obj->y(); // ERROR

58

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 !"#$%
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.

El principio de sustitucin

Todos los LOO soportan subtipos.

Lengua es fuertemente tipados !tipado est"tico#

$aracteri%an los ob etos por su clase $aracteri%an los ob etos por su comportamiento
Lengua e debilmente tipado& funcion medir(objeto) { si (objeto <= 5) sino si (objeto == 0) ...}

Lengua es debilmente tipados !tipado din"mico#

Lengua e fuertemente tipado& funcion medir(objeto: Medible) {...}

El principio de sustitucin

C++& 'ubtipos slo a trav(s de punteros o referencias

Java& directamente

class class Dependiente Dependiente {{ public: public: int int cobrar(); cobrar(); void void darRecibo(); darRecibo(); ...}; ...}; class class Panadero Panadero :: public public Dependiente Dependiente {...} {...} Panadero Panadero p; p; Dependiente& .. Dependiente& d1=p; d1=p; // // sustit sustit Dependiente* .. Dependiente* dd =&p; =&p; // // sustit sustit Dependiente Dependiente d!=p; d!=p; // NO sustit.: // NO sustit.: object object slicing slicing

class class Dependiente Dependiente {{ public public int int cobrar(); cobrar(); public void public void darRecibo(); darRecibo(); ...}; ...}; class class Panadero Panadero e"tends e"tends Dependiente Dependiente {...} {...} Panadero Panadero pp == ne# ne# Panadero(); Panadero(); Dependiente d1=p; Dependiente d1=p; // // sustit. sustit.

HERENCIA DE INTERFAZ

Ob etivos!

)eutili%acin de conceptos !interfa%# *aranti%ar que se cumple el principio de sustitucin

+mplementacin mediante clases abstractas !$,,# o inter"aces !-ava.$/# y enlace din#$ico.

01)12$+A 31 +2T1)4A5 Tie$po de enlace

6omento en el que se identifica el fragmento de cdigo a e ecutar asociado a un mensa e !llamada a m(todo# o el ob eto concreto asociado a una variable.

EN%ACE E&T'TICO (earl) or static binidin*+! en tiempo de compilacin 'entaja& ()*+*(,+*-

EN%ACE DIN',ICO (late or d)na$ic bindin*+! en tiempo de e ecucin

'entaja& )L(.*/*L*D-D

01)12$+A 31 +2T1)4A5 Tie$po de enlace

Tiempo de enlace de ob etos

Enlace est#tico! el tipo de ob eto que contiene una variable se determina en tiempo de compilacin.
$irculo c7

Enlace din#$ico! el tipo de ob eto al que 8ace referencia una variable no est" predefinido, por lo que el sistema gestionar" la variable en funcin de la naturale%a real del ob eto que referencie durante la e ecucin. Lengua es como 'malltal9 siempre utili%an enlace din"mico con variables.

$,, slo permite enlace din"mico con variables cuando (stos son punteros o referencias, y slo dentro de erarqu:as de 8erencia.

4igura;3 <f = ne> $irculo7 .. ne> Triangulo...

01)12$+A 31 +2T1)4A5 Tie$po de enlace

Tiempo de enlace de m(todos

Enlace est#tico! la eleccin de qu( m(todo ser" el encargado de responder a un mensa e se reali%a en tiempo de compilacin, en funcin del tipo que ten:a el ob eto destino de la llamada en tiempo de compilacin.
TCuentaJoven tcj; TCuenta tc; tc=tcj; // object slicing tc.abonarInteresMensual(); // Enlace esttico: TCuenta::abonarInteresMensual()

Enlace din#$ico la eleccin de qu( m(todo ser" el encargado de responder a un mensa e se reali%a en tiempo de e ecucin, en funcin del tipo correspondiente al ob eto que referencia la variable mediante la que se invoca al m(todo en el instante de la e ecucin del mensa e.

TCuenta* tc = new TCuentaJoven; // sustitucin tc->abonarInteresMensual(); // Enlace dinmico: TCuentaJoven::abonarInteresMensual()

01)12$+A 31 +2T1)4A5 ,-todos virtuales


$%uenta* $%uenta* tc tc == ne# ne# $%uenta&oven; $%uenta&oven; tc->abonarInteresMensual() ;; tc->abonarInteresMensual()
// // Enlace Enlace dinmico: dinmico: TCuentaJoven::abonarInteresMensual() TCuentaJoven::abonarInteresMensual()

La clase derivada sobreescribe el comportamiento de la clase base

'e pretende invocar a ciertos m(todos sobreescritos desde referencias a ob etos de la clase base !aprovec8ando el principio de sustitucin#.

1n muc8os lengua es OO este rasgo es soportado de forma natural& ?or e emplo, en -ava, los m(todos son virtuales por defecto. 1n $,, para que esto sea posible&

1l m(todo debe ser declarado en la clase base como $-todo virtual !mediante la palabra clave virtual#. 1sto indica que tiene enlace din"mico. La clase derivada debe proporcionar su propia implementacin del m(todo.

01)12$+A 31 +2T1)4A5 ,-todos virtuales


class class $%uenta $%uenta {{ ... ... virtual virtual void void abonarInteresMensual(); abonarInteresMensual(); }; }; $%uenta* tc = ne# $%uenta&oven; delete tc; // '(u) destructor se invoca* +$%uenta()
@ueremos destruir el ob eto de tipo Tcuenta-oven a trav(s de un puntero a Tcuenta 2ecesitamos que el destructor de la clase base tenga enlace din"mico.

class class $%uenta $%uenta {{ ... ... virtual virtual ~T ~T uenta(); uenta(); }; }; delete tc; // '(u) destructor se invoca* +$%uenta&oven()

01)12$+A 31 +2T1)4A5 ,-todos virtuales ) el principio de sustitucin


class class $%uenta $%uenta {{ ... ... virtual virtual void void abonar,nteres-ensual(); abonar,nteres-ensual(); virtual ;; virtual ~T ~T uenta!irtual() uenta!irtual() }}

1n resumen, si una clase tiene m(todos virtuales 1s posible utili%ar el principio de sustitucin. 0eredar de ella y sobreescribir los m(todos virtuales ?ara destruir ob etos derivados desde punteros a clase base, el destructor de esta clase base debe declararse como m(todo virtual.

01)12$+A 31 +2T1)4A5 Clases abstractas

Alguno de sus m(todos no est" definido& son m(todos abstractos 2o se pueden crear ob etos de estas clases. ': se pueden crear referencias !o punteros# a ob eto de una clase abstracta !que apuntar"n a ob etos de clases derivadas#

?ropsito& *aranti%ar que las clases derivadas proporcionan una implementacin propia de ciertos m(todos. 'e garanti%a el principio de sustitucin.

01)12$+A 31 +2T1)4A5

Clases abstractas

Las clases que deriven de clases abstractas !o interfaces# deben implementar todos los m(todos abstractos !o ser"n a su ve% abstractas#. La clase derivada implementa el interfa% de la clase abstracta.

01)12$+A 31 +2T1)4A5
2otacin U6L para clases abstractas

Vehculo

CLASE ABSTRACTA

CLASE ABSTRACTA
Terrestre {abstract}

CLASE ABSTRACTA

Areo

Coche

Bicicleta

Avin

Helicptero

CLASES CONCRETAS

01)12$+A 31 +2T1)4A5

$lases abstractas en $,,

$lases que contiene al menos un $etodo virtual puro !m(todo abstracto#&


$lase abstracta $lase derivada class class %irculo %irculo :: public public 2or0a 2or0a {{ int int radio; radio; public: public: void ;; void dibu5ar() dibu5ar() $...% $...% ... ... }}

virtual .tipo devuelto/ 0etodo(.lista ar1s/) " #;


class class 2or0a 2or0a {{ int int pos"3 pos"3 pos4; pos4; public: public: virtual "" #; virtual void void dibu5ar() dibu5ar() #; int 1etPosicion6() int 1etPosicion6() {{ return return pos"; pos"; }} ... ... }}

Los m(todos abstractos tienen enlace din"mico !son m(todos virtuales#

01)12$+A 31 +2T1)4A5

$lases abstractas en -ava


abstract class { ... abstract .tipo devuelto/ 0etodo(.lista ar1s/); }
$lase abstracta

abstract abstract class class 2or0a 2or0a {{ private private int int pos"3 pos"3 pos4; pos4; public abstract void ;; public abstract void dibu5ar() dibu5ar() public public int int 1etPosicion6() 1etPosicion6() {{ return return pos"; pos"; }} ... ... }}

$lase derivada class class %irculo %irculo e"tends e"tends 2or0a 2or0a {{ private private int int radio; radio; public void dibu5ar() public void dibu5ar() $...% ;; $...% ... ... }}

01)12$+A 31 +2T1)4A5

Inter"aces

3eclaracin de un con unto de m(todos abstractos. 1n $,,, son clases abstractas donde todos sus m(todos son abstractos y no eAisten atributos de instancia.

Las clases derivadas 8eredan el interfa% mediante 8erencia pblica

-ava.$/& declaracin eApl:cita de interfaces

Las clases pueden implementar m"s de un interfa% !8erencia mltiple de interfaces#

01)12$+A 31 +2T1)4A5
2otacin U6L para interfaces
<<interface>>

Vehculo

INTERFAZ

CLASE ABSTRACTA
Terrestre {abstract}

CLASE ABSTRACTA

Areo

Coche

Bicicleta

Avin

Helicptero

CLASES CONCRETAS

01)12$+A 31 +2T1)4A5

Inter"aces en Java

inter&ace inter&ace 2or0a 2or0a {{ // // 77 8in 8in atributos atributos de de instancia instancia // 7 89lo constantes est:ticas // 7 89lo constantes est:ticas // // 77 $odos $odos los los 0)todos 0)todos son son abstractos abstractos por por de;inici9n de;inici9n void dibu5ar() ; void dibu5ar(); int int 1etPosicion6(); 1etPosicion6(); ... ... }} class class %irculo %irculo i'ple'ents i'ple'ents 2or0a 2or0a {{ private private int int pos"3 pos"3 pos4; pos4; private int radio; private int radio; public public void void dibu5ar() dibu5ar() {...}; {...}; public public int int 1etPosicion6() 1etPosicion6() {...}; {...}; }}

01)12$+A 31 +2T1)4A5

Inter"aces en C,,

class 2or0a class 2or0a { { // 7 8in atributos de instancia // 7 8in atributos de instancia // 7 89lo constantes est:ticas // 7 89lo constantes est:ticas // 7 $odos los 0)todos se declaran abstractos // 7 $odos los 0)todos se declaran abstractos public: public: virtual void dibu5ar()"#; virtual void dibu5ar()"#; virtual int 1etPosicion6()"#; virtual int 1etPosicion6()"#; // resto de 0)todos virtuales puros... // resto de 0)todos virtuales puros... } }

class class %irculo %irculo :: public public 2or0a 2or0a // // (erencia (erencia p)blica p)blica {{ private: private: int int pos"3 pos"3 pos4; pos4; int radio; int radio; public: public: void void dibu5ar() dibu5ar() {...} {...} int 1etPosicion6() int 1etPosicion6() {...}; {...}; }}

01)12$+A 31 +2T1)4A5

1 emplo de interfa% !-ava#


BBinterfaceCC $omparable inter;ace inter;ace %o0parable %o0parable {{ int int co0pare$o(%o0parable co0pare$o(%o0parable o); o); }} class class <ntero <ntero i0ple0ents i0ple0ents %o0parable %o0parable {{ private private int int n; n; <ntero(int <ntero(int i) i) {{ n=i; n=i; }} 1ntero public public int int co0pare$o(%o0parable co0pare$o(%o0parable e) e) {{ <ntero <ntero ee =(<ntero)e; =(<ntero)e; i; (e .n / i; (e .n / n) n) return return 71; 71; else i; (e .n == n) return else i; (e .n == n) return =; =; return 1; return 1; }}

compareTo!$omparable# & int

compareTo!$omparable# & int ... }}

01)12$+A 31 +2T1)4A5

1 emplo de clase abstracta !$,,#


TCuentaAbstracta
# # # # nombre saldo inters numCuentas

TCuentaAbstracta

TCuentaJoven edad" int

+ TCuentaAbstracta() + TCuentaAbstracta(TCuentaAbstracta) + ~TCuenta() + getNombre() const + getSaldo() const + getInteres() const + setSaldo() + setInteres() +abonarInteresMensual(): void +mostrar() <<friend>> o erator<<(!!!)

+ TCuenta#o$en()

+ TCuenta#o$en(TCuenta#o$en) + ~TCuenta#o$en() + get%dad()" int + set%dad(int)" $oid +abonarInteresMensual(): void +mostrar() <<friend>> o erator<<(!!!)

01)12$+A 31 +2T1)4A5
class class $%uenta>bstracta $%uenta>bstracta {{ protected: protected: ... ... public: public: ... ... virtual virtual void void abonarInteresMensual()"#; abonarInteresMensual()"#; }; }; class class $%uenta&oven: $%uenta&oven: public public $%uenta>bstracta $%uenta>bstracta {{ private: private: int int edad; edad; public: public: ... ... // // ,-P?<-<@$>%,A@ ,-P?<-<@$>%,A@ en en clase clase derivada derivada void abonarInteresMensual() { void abonarInteresMensual(){ //no //no inter)s inter)s si si el el saldo saldo es es in;erior in;erior al al lB0ite lB0ite i; (1et8aldo()/=1====){ i; (1et8aldo()/=1====){ set8aldo(1et8aldo()*(1C1et,nteres()/1 set8aldo(1et8aldo()*(1C1et,nteres()/1 /1==)); /1==)); }} }; }; // si1ue... // si1ue...

01)12$+A 31 +2T1)4A5
DUpcasting a clase abstractaE
$%uenta&oven $%uenta&oven tc5; tc5; '' $%uenta $%uenta tc tc == ($%uenta)tc5; ($%uenta)tc5; ** '' $%uenta* $%uenta* ptc ptc == ($%uenta ($%uenta *) *) &tc5; &tc5; ** '' $%uenta& $%uenta& rtc rtc == ($cuenta ($cuenta &) &) tc5; tc5; ** $%uenta&oven $%uenta&oven tc5; tc5; $%uenta* $%uenta* ptc ptc == &tc5; &tc5; $%uenta& $%uenta& rtc rtc == tc5; tc5;

1 ercicio& ?ago de 2minas


TEmpleado string nombre

TFijo double sueldo + + + + T+i,o() T+i,o(T+i,o )) ~T+i,o() setSueldo()

TComisionista double base& comisi'n& $entas( + TComisionista() + TComisionista(TComisionista )) + ~TComisionista() + setComisi'n() + getComisi'n() const + set*ase() + get*ase() const

1 ercicio& ?ago de 2minas


+mplementa las clases anteriores aFadiendo un m(todo get'alario!#, que en el caso del empleado fi o devuelve el sueldo y en el caso del comisionista devuelve la base m"s la comisin, de manera que el siguiente cdigo permita obtener el salario de un empleado independientemente de su tipo.

int int 0ain(){ 0ain(){ int int tipo; tipo; <0pleado <0pleado *eptr; *eptr; cout..D,ntroduce cout..D,ntroduce tipoE..endl; tipoE..endl; cin//tipo; //1:;i5o3 cin//tipo; //1:;i5o3 co0isionista co0isionista s#itcF (tipo){ s#itcF (tipo){ case case 1: 1: eptr=ne# eptr=ne# 2i5o(); 2i5o(); breaG; breaG; case case :eptr=ne# :eptr=ne# %o0isionista(); %o0isionista(); breaG; breaG; }} eptr7/1et8alario(); eptr7/1et8alario(); delete delete eptr; eptr; }}

HERENCIA DE IMPLEMENTACIN Uso seguro

Herencia de implementacin
!

Habilidad para que una clase herede parte o toda su implementacin de otra clase. Debe ser utilizada con cuidado.

80

Uso seguro de la herencia de implementacin


!

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
! !

Constreir restricciones Extender funcionalidad

81

Uso seguro de la herencia de implementacin


!

Especializacin
!

La clase derivada es una especializacin de la clase base: aade comportamiento pero no modifica nada
! !

Satisface las especificaciones de la clase base Se cumple el principio de sustitucin (subtipo)


Ventana mostrar()

OK!
VentanaDeTexto editar()
82

Uso seguro de la herencia de implementacin


!

Especificacin
!

La clase derivada es una especificacin de una clase base abstracta o interfaz.


!

! !

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}

PilaDeEnteros
apila(Object) : void desapila() : Object tope() : Object

OK!

apila(Object) : void desapila() : Object tope() : Object

83

Uso inseguro de la herencia de implementacin


!

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()

No se cumple el principio de sustitucin (un pingino no puede volar)


84

Uso inseguro de la herencia de implementacin


!

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.

VentanaColor colorFG colorBG setColorFG() getColorFG()

85

Uso inseguro de la herencia de implementacin


!

Varianza (herencia de conveniencia)


Punto Coordenada_x Coordenada_y Mover()

La implementacin se parece pero semnticamente los conceptos no estn relacionados jerrquicamente (test es-un). INCORRECTA!!!!

Lnea direccion setDireccion()

Solucin: si es posible, factorizar cdigo comn. (p.ej. Ratn y Tableta_Grafica)

86

Herencia de Construccin
!

Tambin llamada Herencia de Implementacin Pura 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 es-un)
! !

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

87

Herencia de Construccin en C++


!

La herencia privada en C++ implementa un tipo de herencia de construccin que s preserva el principio de sustitucin:
!

El hecho de que Pila herede de Array no es visible para el cdigo que usa la pila (Pila no publica el interfaz de Array).
!

Mejor usar composicin si es posible.

Array elementoAt(int i) : Object capacidad() : int numElementos() : int <<private>>

Pila
apila(Object) : void desapila() : Object tope() : Object

88

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
90

Costes de la Herencia
! ! ! !

Velocidad de ejecucin Tamao del programa Sobrecarga de paso de mensajes Complejidad del programa

[BUDD] 8.9
91

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

93

Herencia vs Todo-Parte
!

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).
!

94

Eleccin de tcnica de reuso Introduccin


!

Herencia (IS-A) y Composicin (HAS-A) son los dos mecanismos ms comunes de reuso de software
!

COMPOSICIN (Layering): Relacin tener-un: ENTRE OBJETOS.


Composicin significa contener un objeto. !Ejemplo: Un coche tiene un tipo de motor.
!

class coche {... private: Motor m; };


!

HERENCIA: Relacin ser-un: ENTRE CLASES


Herencia significa contener una clase. !Ejemplo: Un coche es un vehculo
!

class coche: public vehiculo{ }


95

Eleccin de tcnica de reuso Introduccin


!

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.
96

Eleccin de tcnica de reuso Uso de Composicin (Layering)


!

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 clase ya 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; };

97

Eleccin de tcnica de reuso Uso de Composicin (Layering)


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.
!

98

Eleccin de tcnica de reuso Uso de Herencia


!

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 valores repetidos 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).

99

Eleccin de tcnica de reuso Uso de Herencia


!

El uso de la herencia asume que las subclases son adems subtipos.


!

As, las instancias de la nueva abstraccin deberan comportarse de manera similar a las instancias de la clase padre. En nuestro ejemplo, un Conjunto NO ES una Lista.

" En realidad deberamos: " Usar herencia privada " Reescribir todos los mtodos de Conjunto basndo su implementacin en los de Lista.

100

Eleccin de tcnica de reuso Composicin vs. Herencia


!

La composicin es una tcnica generalmente ms sencilla que la herencia.


!

Define ms claramente la interfaz que soporta el nuevo tipo, independientemente de la interfaz del objeto parte.

La composicin es ms flexible (y ms resistente a los cambios)


!

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.

101

Eleccin de tcnica de reuso Composicin vs. Herencia


!

La herencia (pblica) presupone el concepto de subtipo (principio de sustitucin)


!

La herencia permite una definicin ms escueta de la clase


! !

Requiere menos cdigo. Oferta ms funcionalidad: cualquier nuevo mtodo asociado a la clase base estar inmediatamente disponible para todas sus clases derivadas.

La herencia es ligeramente ms eficiente que la composicin (evita una llamada).

Desventajas
!

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.
102

Eleccin de tcnica de reuso Ejemplos Composicin vs. Herencia


!

Clase Persona y clase Empleado


!

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).

Clase Persona y clase Domicilio


!

Clase Lista y clase Nodo de la lista


!

Clase Empresa, clase Empleado y clase Jefe de grupo de empleados


! !

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.
103

You might also like