Publicado el 24 de Enero del 2017
1.321 visualizaciones desde el 24 de Enero del 2017
108,7 KB
44 paginas
Creado hace 16a (24/11/2008)
Tema 3: Herencia en C++
Programación Orientada a Objetos
Curso 2008/2009
Begoña Moros Valle
Contenido
Tipos de herencia
Herencia y niveles de visibilidad
Herencia y creación
Redefinición de métodos
Conversión de tipos
Consulta del tipo dinámico
Clases abstractas
Punteros a función
Iteradores
Herencia múltiple
Tema 3
Herencia
2
Caso de estudio
Deposito
titular
capital
plazoDias
tipoInteres
liquidar
getIntereses
DepositoEstructurado
tipoInteresVariable
capitalVariable
Un depósito estructurado es_un
tipo de depósito
Un depósito estructurado tiene
nuevos atributos
Tipo de interés variable
Capital variable
Redefine parte de la
funcionalidad heredada de
depósito
El método que calcula los intereses
El método que devuelve el capital
Tema 3
Herencia
3
Clase Deposito
class Deposito {
private:
public:
Persona* titular;
double capital;
int plazoDias;
double tipoInteres;
Deposito(…);
double liquidar();
double getIntereses();
double getCapital();
int getPlazoDias();
double getTipoInteres();
Persona* getTitular();
};
Tema 3
Herencia
4
Clase Depósito 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
5
Niveles de visibilidad
private
protected
public
Sólo accesible en la clase
donde se definen las
propiedades
Sólo accesibles por la
clase y sus
descendientes
Accesible desde cualquier
clase
Tema 3
Herencia
6
Herencia pública
class B: public A {...}
Por defecto, se mantiene el nivel de visibilidad
de las propiedades heredadas (= Java)
Se puede ampliar la visibilidad de las
características heredadas
Se puede reducir la visibilidad de las
características heredadas
“agujero de tipos” debido a asignaciones
polimórficas
Tema 3
Herencia
7
Herencia privada
class B: private A {...}
Todas las características de A se heredan como
privadas
Los tipos no son compatibles.
No se permiten hacer asignaciones polimórficas
Es la opción por defecto
Se puede mantener el nivel de visibilidad
original calificando la rutina en el bloque
public o protected
Útil para la herencia de implementación
Heredar de una clase sólo para reutilizar la
implementación
Tema 3
Herencia
8
Constructor de Depósito 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
9
Redefinición de métodos
La clase padre debe indicar que los métodos se pueden
redefinir utilizando el modificador virtual
¿Viola el Principio de Abierto-Cerrado?
Un método en la clase hija que tenga la misma
signatura que un método virtual significa que lo está
redefiniendo
En la definición de la clase hija (fichero cabecera) hay
que incluir los métodos que se redefinen
Para invocar la ejecución de la versión de uno de los
métodos de cualquier otra clase se utiliza la calificación
de rutinas
NombreClase::nombreMétodo
Despotio::getCapital();
Tema 3
Herencia
10
Redefinición de métodos
class Deposito {
private:
public:
Persona* titular;
double capital;
int plazoDias;
double tipoInteres;
Deposito(…);
double liquidar();
virtual double getIntereses();
virtual double getCapital();
int getPlazoDias();
double getTipoInteres();
Persona* getTitular();
};
Tema 3
Herencia
11
Redefinición de métodos
Métodos 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 dinámica
El polimorfismo de asignaciónestá permitido para
entidades con semántica por valor y referencia.
Sólo se consideran que dos métodos están
sobrecargados (polimorfismo ad-hoc) si se definen
dentro del mismo ámbito
Una función de la clase hija con el mismo nombre que una
función heredada con distinta signatura la oculta.
Ligadura dinámica:
Sólo es posible para métodos virtuales.
La entidad polimórfica debe ser de tipo referencia.
Ligadura estática:
Se aplica la versión del método asociada al tipo estático de la
variable.
Tema 3
Herencia
13
Asignaciones polimórficas
Deposito deposito(…);
DepositoEstructurado de(…);
//Asignación polimórfica entre objetos valor
deposito = de;
//Ligadura estática, Deposito::getCapital
cout<<"Capital total "<<deposito.getCapital()<<endl;
Deposito* ptrDeposito = new Deposito(…);
DepositoEstructurado* ptrDe = new DepositoEstructurado(…);
//Asignación polimórfica de punteros
ptrDeposito = ptrDe;
//Ligadura dinámica, DepositoEstructurado::getCapital
cout<<"Capital total "<<ptrDeposito->getCapital()<<endl;
ptrDesposito->liquidar(); //Ligadura estática
Herencia
Tema 3
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 versión redefinida devuelve el capital total
La versión sobrecargada devuelve el capital fijo o variable en
función del parámetro
Tema 3
Herencia
16
Conversión de tipos
Operador dynamic_cast<Tipo*>(ptro)
Convierte el ptro en el puntero a Tipo
ptro debe ser una entidad polimórfica (su clase
debe tener algún método virtual)
La conversión se hace entre tipos compatibles
Si la conversión falla se le asigna cero (puntero
NULL)
También dynamic_cast<Tipo>(ref)
En caso de que la conversión no sea posible se lanza
una excepción (bad_cast)
Tema 3
Herencia
17
Conversión de tipos
Establecemos el tipo de interés variable a los
depósitos 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 dinámico
Contamos el número de depósitos 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
capital
plazoDias
tipoInteres
liquidar
getIntereses
Cuenta
saldo
ingreso
reintegro
getBeneficio es un
método abstracto
ProductoFinanciero
debe ser una clase
abstracta
Tema 3
Herencia
20
Clases abstractas
No existe una palabra reservada para indicar que una
clase es abstracta
Una clase es abstracta si contiene un método 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
múltiple.
Si una clase quiere ser compatible con varios tipos,
basta con que herede públicamente de otras clases.
El equivalente a las interfaces de Java sería una
clase totalmente abstracta sólo con
métodos virtuales puros.
Tema 3
Herencia
22
Acciones
Para poder pasar una acción como parámetro
de una función podemos utilizar dos
estrategias:
Punteros a función:
En C++ es posible pasar una función como parámetro
Clase que represente la acción:
Definir una clase totalmente abstracta que simule la interfaz
de Java
Definir una subclase por cada acción que se necesite
implementar
Tema 3
Herencia
23
Acciones mediante punteros a función
Un puntero a función es una variable que
guarda la dirección de comienzo de la función
Puede considerarse como una especie de
“alias” de la función que hace que pueda
pasarse como parámetro a otras funciones
Las reglas del paso de parámetros se aplican
también para el paso de funciones como parámetro
X (*fptr) (A);
fptr es un puntero a función que recibe A como
argumento y devuelve X
Tema 3
Comentarios de: Tema 3: Herencia en C++ (0)
No hay comentarios