clase Base

Transcripción

clase Base
Programación I
Unidad 5
Herencia
Herencia
•Junto con el polimorfismo, es la característica
más importante de la POO.
•Permite reutilizar código, definiendo
clases a partir de otras ya existentes.
nuevas
•Si una clase B hereda de otra clase A, a A la
llamaremos clase base o padre, mientras que
B será una subclase o hija de A.
•Si una clase hereda de otra, en particular hereda
todos sus métodos y atributos, pudiendo además
declarar y definir más atributos y métodos, y
redefinir algunos de los métodos heredados.
Herencia: Sintaxis
Sintaxis:
class B : TipoHerencia A {....};
indica que la clase B hereda de la clase A.
El TipoHerencia especifica el tipo de
herencia, que en C++ puede ser: public,
protected y private.
class B : public A {....};
Si no se pone TipoHerencia se asume
que la herencia es privada.
Herencia: Niveles de protección
•Además de los niveles de protección, para
atributos y métodos, private y public, existe
protected, para las subclases.
•En la implementación de la clase B, subclase de
A, podemos utilizar todos los atributos públicos y
protegidos (protected) de la clase A, pero no los
privados.
•La nueva declaración protected para métodos
y atributos indica que estos pueden ser utilizados
dentro de la implementación de una clase que
herede de ella. En cualquier otra situación se
comportan como atributos privados.
Herencia: Niveles de protección
Declaración del
método o
atributo
¿Accesible
desde la propia
clase?
¿Accesible
desde
subclases?
¿Accesible para
los demás?
public
SI
SI
SI
private
SI
NO
NO
protected
SI
SI
NO
Herencia: ejemplo
class Base {
private: // no accesible desde las subclases
int x,y;
protected: // accesible desde las subclases
int nx,ny;
public: // accesible para todos
Base():x(0),y(0),nx(0),ny(0){};
Base(int a,int b):x(a),y(b),nx(0),ny(0){};
Lista de inicializaciones
// métodos inline
void set(int a,int b,int c,int d)
{x=a;y=b;nx=c;ny=d;}
int getX()const {return x;}
int getY()const {return y;}
int getNX()const {return nx;}
int getNY()const {return ny;}
};
Herencia: ejemplo
class Hija:public Base{
private:
int p1,p2;
public:
void actualizaNXNY(){
p1=nx; // CORRECTO
p2=y+ny; // INCORRECTO
set(2,3,p1,p2); // CORRECTO
};
void actualizaXY()
{p1=getX(); p2=getY();}; // CORRECTO
int getP1()const {return p1;}
int getP2()const {return p2;};
};
Herencia: constructores
Supongamos que declaramos la variable:
Hija h;
¿Qué constructor se ejecuta?
Como la clase Hija no tiene definido ningun constructor,
se ejecuta su constructor por defecto, que lo primero que
hace es invocar al constructor por defecto de la clase
Base.
Si añadimos a la clase Hija:
Hija(){set(1,1,1,1);p1=5;p2=7;}
se ejecutarán:
1. El constructor sin argumentos de la clase Base.
2. El constructor sin argumentos de la clase Hija.
Herencia: constructores
Cuando se crea un objeto de una subclase, siempre se
invoca en primer lugar (implícita o explícitamente) a un
constructor de la clase base.
Implícitamente: Si no se especifica uno, se ejecuta el
constructor por defecto de la clase base.
Hija(int a,int b):p1(a+2),p2(b+2){};
Explícitamente: mediante la lista de inicializaciones en
el constructor de la subclase.
Hija(int a,int b):Base(a,b),p1(a+2),p2(b+2){};
Herencia: destructores
Para el caso de los destructores, cuando se
destruye un objeto de una subclase, se invoca
primero al destructor de la subclase y al final se
invoca al destructor de la clase base. Siempre de
forma implícita, pues sólo existe un destructor por
clase.
Herencia: Redefinición de métodos
Una subclase puede “redefinir” métodos de la clase base:
clase Base {
.....
int suma(){
ShowMessage(“Clase Base”);
return nx+ny+x+y;}
}
clase Hija: public Base {
......
int suma(){
ShowMessage(“Clase Hija”);
return px+py;}
}
Herencia: Redefinición de métodos
¿Cómo funciona?
Enlace estático, el de la clase declarada para la
variable (se decide en tiempo de compilación).
Hija h(2,3);
ShowMessage(h.suma()); Clase Hija
Base b(2,3);
ShowMessage(b.suma()); Clase Base
Herencia: Casting
¿Qué hacer si queremos que h ejecute el método
suma de la clase Base?
// casting hacia arriba
ShowMessage(((Base) h).suma());
¿Es correcto: ?
b=h; // POLIMORFISMO
b.suma();
¿Qué pasa con los atributos p1 y p2 que no tiene b?
¿Qué método se ejecuta? El de la clase Base
Herencia: Enlace estático
Enlace estático (i.e. en tiempo de compilación). Se
ejecutan los métodos de la clase a la que pertenece la
variable declarada y no del posible objeto que contiene.
¿Es correcto?
ShowMessage((Hija b).suma())
h=b;
h.suma();
NO: Error de compilación. b no tiene los atributos p1 y p2
de la clase Hija !!!
Herencia: Enlace dinámico
Para conseguir que se ejecutara el método suma de la clase Hija
(objeto contenido en la variable b) necesitaríamos métodos virtuales
con enlace dinámico (i.e. en tiempo de ejecución), que sólo tienen
sentido en presencia de punteros y referencias).
clase Base {
.......
virtual int suma(){....}
};
Hija h(2,3);
Base* b = &h;
ShowMessage(b->suma()); // enlace dinámico
Herencia: Enlace dinámico
Conclusión: Utilizaremos el polimorfismo con PUNTEROS.
Observación: Si en la clase Hija quisiéramos utilizar el método
suma de la clase Base, debemos utilizar la notación:
Base::suma()
Por ejemplo:
class Hija:public Base{
.........
virtual int suma(){
ShowMessage("Clase hija");
return Base::suma()+p1+p2;}
};

Documentos relacionados