Sunteți pe pagina 1din 44

Tema 3: Herencia en C++

Programacin Orientada a Objetos


Curso 2008/2009
Begoa Moros Valle

Contenido

Tipos de herencia
Herencia y niveles de visibilidad
Herencia y creacin
Redefinicin de mtodos
Conversin de tipos
Consulta del tipo dinmico
Clases abstractas
Punteros a funcin
Iteradores
Herencia mltiple
Tema 3

Herencia

Caso de estudio
Deposito
titular
capital
plazoDias
tipoInteres
liquidar
getIntereses

Tema 3

Un depsito estructurado tiene


nuevos atributos

DepositoEstructurado
tipoInteresVariable
capitalVariable

Un depsito estructurado es_un


tipo de depsito

Tipo de inters variable


Capital variable

Redefine parte de la
funcionalidad heredada de
depsito

El mtodo que calcula los intereses


El mtodo que devuelve el capital
Herencia

Clase Deposito
class Deposito {
private:
Persona* titular;
double capital;
int plazoDias;
double tipoInteres;
public:
Deposito();
double liquidar();
double getIntereses();
double getCapital();
int getPlazoDias();
double getTipoInteres();
Persona* getTitular();
};
Tema 3

Herencia

Clase Depsito Estructurado


class DepositoEstructurado: public Deposito{
private:
double tipoInteresVariable;
double capitalVariable;
public:
DepositoEstructurado(Persona titular, double capital, int
plazoDias,double tipoInteres, double tipoInteresVariable,
double capitalVariable);
double getInteresesVariable();
void setTipoInteresVariable(double interesVariable);
double getTipoInteresVariable();
double getCapitalVariable();
};
Tema 3

Herencia

Niveles de visibilidad
private

protected

public

Tema 3

Slo accesible en la clase


donde se definen las
propiedades
Slo accesibles por la
clase y sus
descendientes
Accesible desde cualquier
clase

Herencia

Herencia pblica
class B: public A {...}

Por defecto, se mantiene el nivel de visibilidad


de las propiedades heredadas (= Java)
Se puede ampliar la visibilidad de las
caractersticas heredadas
Se puede reducir la visibilidad de las
caractersticas heredadas
agujero de tipos debido a asignaciones
polimrficas
Tema 3

Herencia

Herencia privada

class B: private A {...}


Todas las caractersticas de A se heredan como
privadas
Los tipos no son compatibles.

No se permiten hacer asignaciones polimrficas

Es la opcin por defecto


Se puede mantener el nivel de visibilidad
original calificando la rutina en el bloque
public o protected
til para la herencia de implementacin

Heredar de una clase slo para reutilizar la


implementacin

Tema 3

Herencia

Constructor de Depsito Estructurado

Los constructores no se heredan (= Java)


El constructor de la clase hija (clase derivada)
siempre tiene que invocar al constructor de la
clase padre (clase base)

DepositoEstructurado::DepositoEstructurado(Persona titular,
double capital, int plazoDias, double tipoInteres, double
tipoInteresVariable, double capitalVariable):Deposito(titular,
capital, plazoDias, tipoInteres){
this.tipoInteresVariable = tipoInteresVariable;
this.capitalVariable = capitalVariable;
}
Tema 3

Herencia

Redefinicin de mtodos

La clase padre debe indicar que los mtodos se pueden


redefinir utilizando el modificador virtual

Un mtodo en la clase hija que tenga la misma


signatura que un mtodo virtual significa que lo est
redefiniendo

Viola el Principio de Abierto-Cerrado?

En la definicin de la clase hija (fichero cabecera) hay


que incluir los mtodos que se redefinen

Para invocar la ejecucin de la versin de uno de los


mtodos de cualquier otra clase se utiliza la calificacin
de rutinas

NombreClase::nombreMtodo
Despotio::getCapital();

Tema 3

Herencia

10

Redefinicin de mtodos
class Deposito {
private:
Persona* titular;
double capital;
int plazoDias;
double tipoInteres;
public:
Deposito();
double liquidar();
virtual double getIntereses();
virtual double getCapital();
int getPlazoDias();
double getTipoInteres();
Persona* getTitular();
};
Tema 3

Herencia

11

Redefinicin de mtodos

Mtodos redefinidos en DepositoEstructurado

//Override
double DepositoEstructurado::getIntereses() {
return Deposito::getIntereses() + getInteresesVariable();
}

//Override
double DepositoEstructurado::getCapital() {
return Deposito::getCapital() + getCapitalVariable();
}

Invocan a las versiones definidas en la clase Deposito


Tema 3

Herencia

12

Polimorfismo y Ligadura dinmica

El polimorfismo de asignacin est permitido para


entidades con semntica por valor y referencia.
Slo se consideran que dos mtodos estn
sobrecargados (polimorfismo ad-hoc) si se definen
dentro del mismo mbito

Ligadura dinmica:

Una funcin de la clase hija con el mismo nombre que una


funcin heredada con distinta signatura la oculta.
Slo es posible para mtodos virtuales.
La entidad polimrfica debe ser de tipo referencia.

Ligadura esttica:

Se aplica la versin del mtodo asociada al tipo esttico de la


variable.

Tema 3

Herencia

13

Asignaciones polimrficas
Deposito deposito();
DepositoEstructurado de();
//Asignacin polimrfica entre objetos valor
deposito = de;
//Ligadura esttica, Deposito::getCapital
cout<<"Capital total "<<deposito.getCapital()<<endl;
Deposito* ptrDeposito = new Deposito();
DepositoEstructurado* ptrDe = new DepositoEstructurado();
//Asignacin polimrfica de punteros
ptrDeposito = ptrDe;
//Ligadura dinmica, DepositoEstructurado::getCapital
cout<<"Capital total "<<ptrDeposito->getCapital()<<endl;
ptrDesposito->liquidar();
//Ligadura
esttica
Tema 3
Herencia

14

Sobrecarga en C++
class Deposito {

public:
virtual double getCapital();
};
class DepositoEstructurado: public Deposito{

public:
double getCapital(bool tipo);
};

getCapital est definido en distinto mbito


getCapital no est sobrecargado en la clase
DepositoEstructurado
Tema 3

Herencia

15

Sobrecarga en C++
class Deposito {

public:
virtual double getCapital();
};
class DepositoEstructurado: public Deposito{

public:
double getCapital();
double getCapital(bool tipo);
};

getCapital est sobrecargado

La versin redefinida devuelve el capital total


La versin sobrecargada devuelve el capital fijo o variable en
funcin del parmetro

Tema 3

Herencia

16

Conversin de tipos

Operador dynamic_cast<Tipo*>(ptro)

Convierte el ptro en el puntero a Tipo


ptro debe ser una entidad polimrfica (su clase
debe tener algn mtodo virtual)
La conversin se hace entre tipos compatibles
Si la conversin falla se le asigna cero (puntero
NULL)

Tambin dynamic_cast<Tipo>(ref)

En caso de que la conversin no sea posible se lanza


una excepcin (bad_cast)

Tema 3

Herencia

17

Conversin de tipos

Establecemos el tipo de inters variable a los


depsitos estructurados

Deposito** productos;
depositos = new Deposito*[MAX_DEPOSITOS];

DepositoEstructurado* depEst;

for (int i =0; i<MAX_DEPOSITOS; i++){


depEst = dynamic_cast<DepositoEstructurado*>(depositos[i]);
if (depEst != NULL)
depEst->setTipoInteresVariable(0.05);
}
Tema 3

Herencia

18

Consulta del tipo dinmico

Contamos el nmero de depsitos abiertos

int numDepositos = 0;

for (int i =0; i<MAX_PRODUCTOS; i++){


if (dynamic_cast<Deposito*>(productos[i]))
++numDepositos;

Equivalente a instanceof de Java


Tema 3

Herencia

19

Clases abstractas
ProductoFinanciero
titular
getImpuestos
getBeneficio

double getImpuestos() {
return getBeneficio() * 0.18;
}

Deposito

Cuenta

capital
plazoDias
tipoInteres
liquidar
getIntereses

saldo
ingreso
reintegro

Tema 3

getBeneficio es un
mtodo abstracto
ProductoFinanciero
debe ser una clase
abstracta

Herencia

20

Clases abstractas

No existe una palabra reservada para indicar que una


clase es abstracta
Una clase es abstracta si contiene un mtodo virtual
puro
class ProductoFinanciero{
private:
Persona* titular;
public:
ProductoFinanciero(Persona* titular);
virtual double getBeneficio()=0;
double getImpuestos();
Persona* getTitular();
};
Tema 3

Herencia

21

Interfaces

C++ no define el concepto de interfaz de


Java.
No es necesario, ya el lenguaje ofrece herencia
mltiple.

Si una clase quiere ser compatible con varios tipos,


basta con que herede pblicamente de otras clases.

El equivalente a las interfaces de Java sera una


clase totalmente abstracta slo con
mtodos virtuales puros.
Tema 3

Herencia

22

Acciones

Para poder pasar una accin como parmetro


de una funcin podemos utilizar dos
estrategias:

Punteros a funcin:

En C++ es posible pasar una funcin como parmetro

Clase que represente la accin:

Tema 3

Definir una clase totalmente abstracta que simule la interfaz


de Java
Definir una subclase por cada accin que se necesite
implementar

Herencia

23

Acciones mediante punteros a funcin

Un puntero a funcin es una variable que


guarda la direccin de comienzo de la funcin
Puede considerarse como una especie de
alias de la funcin que hace que pueda
pasarse como parmetro a otras funciones

Las reglas del paso de parmetros se aplican


tambin para el paso de funciones como parmetro

X (*fptr) (A);

fptr es un puntero a funcin que recibe A como


argumento y devuelve X

Tema 3

Herencia

24

Punteros a funcin
namespace banco{
class Sucursal{
private:
ProductoFinanciero** productos;
public:
Sucursal();
ProductoFinanciero* buscar(
bool (*condicion) (ProductoFinanciero*));
};
//Condiciones de bsqueda
bool depositoAlto (ProductoFinanciero* producto);
}

El parmetro del mtodo buscar es una funcin que recibe como


parmetro un puntero a un ProductoFinanciero y devuelve un
valor booleano.

Por ejemplo, la funcin depositoAlto

Tema 3

Herencia

25

Mtodo genrico de bsqueda


ProductoFinanciero* Sucursal::buscar(
bool (*condicion)(ProductoFinanciero*)){
bool encontrado = false;
for (int i =0; i<MAX_PRODUCTOS; i++)
if (condicion(productos[i])){
encontrado = true;
return productos[i];
}
if (!encontrado) return NULL;
}

Tema 3

Herencia

26

Condicin de bsqueda

La funcin depositoAlto NO puede ser un mtodo de


instancia. La definimos dentro del espacio de
nombres.

bool banco::depositoAlto(ProductoFinanciero* producto){


Deposito* deposito = dynamic_cast<Deposito*>(producto);
if (deposito!= NULL)
return (deposito->getCapital()>1000);
else return false;
}
Sucursal cam;

ProductoFinanciero* producto = cam.buscar(depositoAlto);


Tema 3

Herencia

27

Clase que representa la accin

Interfaz Condicion Clase totalmente abstracta


template <class T> class Condicion{
public:
virtual bool test(T elemento) = 0;
};

Habra que definir una subclase por cada criterio de


bsqueda
Por ejemplo, CondicionCapital, buscamos, de entre
todos los productos financieros del banco aquellos
depsitos con un capital superior a un determinado
valor umbral.
Tema 3

Herencia

28

Mtodo genrico de bsqueda


ProductoFinanciero* Banco::buscar
(Condicion<ProductoFinanciero*>* condicion){
bool encontrado = false;
for (int i =0; i<MAX_PRODUCTOS; i++)
if (condicion->test(productos[i])){
encontrado = true;
return productos[i];
}
if (!encontrado) return NULL;
}

Tema 3

Herencia

29

Implementacin de una condicin


class CondicionCapital: public Condicion<ProductoFinanciero*>{
private:
double capitalUmbral;
public:
CondicionCapital(double capital);
bool test(ProductoFinanciero* elemento);
};
bool CondicionCapital::test(ProductoFinanciero* elemento){
Deposito* deposito = dynamic_cast<Deposito*>(elemento);
if (deposito!= NULL)
return (deposito->getCapital()>capitalUmbral);
else return false;
}
Tema 3

Herencia

30

Clase que representa la accin

Para invocar al mtodo de bsqueda hay que


crear un objeto del tipo de condicin que se
vaya a utilizar

Sucursal sucursal;

ProductoFinanciero* producto;
CondicionCapital* cc = new CondicionCapital(1000);
producto = sucursal.buscar(cc);

Tema 3

Herencia

31

Herencia mltiple

En C++ es posible que una clase tenga ms de


una clase padre
Problemas:

Colisin de nombres: la clase hija hereda dos


mtodos efectivos con el mismo nombre y diferentes
implementaciones

Si se redefine el mtodo en la clase hija se funden las dos


versiones en una nueva
Si se necesitan las dos funciones se deben calificar las
rutinas para resolver la ambigedad.

Herencia repetida: una clase se hereda dos veces

Tema 3

Herencia

32

Herencia repetida
class CuentaRemunerada: public Cuenta, public Deposito{

};
ProductoFinanciero
titular

Deposito

Cuenta

CuentaRemunerada
Tema 3

CuentaRemunerada
hereda dos veces de
ProductoFinanciero
Existe dos campos
titular en
CuentaRemunerada?
Conflicto de nombres con
el mtodo getBeneficio

Herencia

33

Herencia repetida

Por defecto en C++ se duplican todos los


atributos heredados
titular
atributos Deposito
titular
atributos Cuenta
at. CtaRemunerada
Estructura de un objeto CuentaRemunerada
Tema 3

Herencia

34

Herencia repetida

El mtodo getTitular se hereda dos veces


colisin de nombres
La llamada getTitular (sin calificar) sobre
una cuenta remunerada es ambigua.
Hay que resolver la ambigedad mediante la
calificacin de rutinas y atributos

CuentaRemunerada* cr = new CuentaRemunerada();


cout<<Titular "<<cr->Cuenta::getTitular()->getNombre();

Tema 3

Herencia

35

Asignaciones polimrficas

Hay dos objetos ProductoFinanciero en un


objeto CuentaRemunerada
La asignacin entre ambas clases es ambigua
ProductoFinanciero* pf;
CuentaRemunerada* cr = new ;
pf = cr; //Error en tiempo de compilacin

Solucin: establecer el camino


ProductoFinanciero* pf;
CuentaRemunerada* cr = new CuentaRemunerada();

pf = (Cuenta*)cr;
Tema 3

Herencia

36

Asignaciones polimrficas ambiguas

La aplicacin del mtodo getBeneficio sobre


un objeto CuentaRemunerada es ambigua

Si no se hace la llamada el compilador no avisa del


conflicto de nombres

ProductoFinanciero* pf;
CuentaRemunerada* cr = new CuentaRemunerada();

pf = (Cuenta*)cr;

cout<<"Cuenta remunerada "<<pf->getTitular()->getNombre()<<endl;


cout<<"beneficio "<<pf->getBeneficio()<<endl;
cout<<"Beneficio de cr "<<cr->getBeneficio()<<endl; //Error
Tema 3

Herencia

37

Herencia virtual

Si queremos que la clase CuentaRemunerada


herede una nica copia de
ProductoFinanciero, las clases intermedias
tienen que declarar su herencia como
virtual.
Se resuelve la ambigedad de las asignaciones
polimrficas
Slo debe existir una versin de los mtodos
heredados

El compilador detecta que se estn heredando dos


versiones del mtodo getBeneficio

Tema 3

Herencia

38

Herencia virtual
class ProductoFinanciero{

};
class Deposito: virtual public ProductoFinanciero {

};
class Cuenta:

};

virtual public ProductoFinanciero {

class CuentaRemunerada: public Cuenta, public Deposito{

};

Tema 3

Herencia

39

Constructores y herencia virtual

El constructor de la clase CuentaRemunerada


tiene que llamar al constructor de
ProductoFinanciero aunque no sea una
clase de la que hereda directamente.

CuentaRemunerada::CuentaRemunerada(Persona* p, double s, int


plazoDias,double tipoInteres)
:ProductoFinanciero(p),
Cuenta(p,s),
Deposito(p, s, plazoDias, tipoInteres){

}
Tema 3

Herencia

40

Herencia repetida virtual


El mtodo getBeneficio() es definido por Cuenta y
Deposito: colisin de nombres.

Error en tiempo de compilacin no existe una nica versin

class CuentaRemunerada: public Cuenta, public Deposito{


public:
CuentaRemunerada();
double getBeneficio();
};

Se evita al redefinir el mtodo eligiendo una de las


versiones:

double CuentaRemunerada::getBeneficio(){
return Deposito::getBeneficio();
}
Tema 3

Herencia

41

Asignaciones polimrficas
ProductoFinanciero* pf;
CuentaRemunerada* cr = new CuentaRemunerada();

pf = cr;

cout<<"Cuenta remunerada "<<pf->getTitular()->getNombre()<<endl;


cout<<"beneficio "<<pf->getBeneficio()<<endl;

No existe ambigedad en la asignacin


Se ejecuta el mtodo getBeneficio
disponible en CuentaRemunerada
Tema 3

Herencia

42

Funcin dominante

Si un mtodo de la clase ProductoFinanciero


se redefine slo en una de las clases hijas, no
existe ambigedad
Se dice que la versin redefinida domina sobre
la versin original
En el caso de una asignacin polimrfica se
ejecutar la versin dominante.

Tema 3

Herencia

43

Herencia de C++ vs. Java

La herencia en C++ es diferente a Java en


varios aspectos:

Herencia mltiple: una clase puede heredar de


varias clases.
Herencia privada: heredar de una clase slo el
cdigo, pero no el tipo.
Redefinicin de mtodos: por defecto, los
mtodos de una clase no pueden ser redefinidos.
No existe el tipo Object raz de la jerarqua de
clases.

Tema 3

Herencia

44

S-ar putea să vă placă și