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