La descarga está en progreso. Por favor, espere

La descarga está en progreso. Por favor, espere

Pablo San Segundo (C-206) pablo.sansegundo@upm.es Herencia Pablo San Segundo (C-206) pablo.sansegundo@upm.es.

Presentaciones similares


Presentación del tema: "Pablo San Segundo (C-206) pablo.sansegundo@upm.es Herencia Pablo San Segundo (C-206) pablo.sansegundo@upm.es."— Transcripción de la presentación:

1 Pablo San Segundo (C-206) pablo.sansegundo@upm.es
Herencia Pablo San Segundo (C-206)

2 Índice Nociones generales Derivación pública
Construcción y destrucción Conversiones entre clase derivada y base Operador asignación Derivación protegida Derivación privada

3 Noción de herencia I. El mecanismo de herencia es una característica de la POO que permite extender o especificar una clase predefinida denominada clase base añadiendo nuevos atributos o métodos. La nueva clase recibe el nombre de clase derivada. Mamifero Generalización Especialización Es-Un II. El mecanismo de herencia es recursivo. Las clases derivadas pueden, a su vez, ser clases base de una nueva derivación formando una jerarquía de clases. Perro Es-Un III. NO es un FIN, es un MEDIO para la reutilización de código (gestión y mantenimiento de colecciones de tipos); debe usarse con mesura y tras un profundo análisis. Caniche

4 Derivación pública en C++
class <clase derivada> : public <clase base> Los miembros públicos de la clase base son también públicos en la clase derivada, por tanto accesibles también al usuario de la clase derivada. Los miembros privados de la clase base NO son accesibles en la clase derivada. Es el concepto intuitivo de “herencia” en la POO. class Perro: public Mamifero{ //… }; class Caniche: public Perro{

5 Comportamiento: accesibilidad a clase Base
Acceso desde el exterior Acceso desde la clase derivada Acceso desde el exterior Acceso desde futuras derivaciones

6 Ejercicio-Punto (1/2) Implemente una clase Punto con dos coordenadas
Generalice Punto con una clase ObjetoPunto de las siguientes maneras: Sintaxis: Añada un tipo enumerado en ObjetoPunto para representar el punto como una CRUZ, una ESTRELLA o un CIRCULO Con Estado: Añada un identificador entero id a cada Punto Especialice Punto con una clase PuntoCol que contenga un dato enumerado con colores posibles AZUL, BLANCO o NEGRO Test unitario para la jerarquía

7 Ejercicio-Punto (2/2)

8 Algunas intuiciones fundamentales
EJERCICIO Comente el alumno acerca de las siguientes aseveraciones indicando si son ciertas o falsas y justificando la respuesta La derivación pública representa una relación ES-UN Una clase Base contiene características comunes de todas sus clases Derivadas En la derivación pública se hereda el interfaz (parte pública) de la clase Base La derivación pública puede representar también las relaciones: Contiene-a Está-implementado-por

9 Sobre aves y pingüinos

10 Sobre rectángulos y cuadrados
class Rectangulo{ int altura; int anchura; public: void setAnchura(int anchura); void setAltura(int anchura); int altura(); int anchura(); }; class Cuadrado: public Rectangulo{…} void ensanchar(Rectangulo &r){ r.setAnchura(r.anchura()+15); } Cuestión ¿Es adecuada esta relación de herencia?

11 Nivel de permisos ‘protected’
Una clase derivada NO tiene acceso a los miembros privados de la clase base. Se emplea el calificativo protected para eliminar esa protección. Un miembro protected de la clase base es accesible desde la definición de la clase derivada. El usuario de la clase derivada sólo puede acceder al interfaz (parte pública) de la clase base . class PuntoCol : public Punto{ string col; public: //… set(double x, double y, string color){ col=color; Punto::x=x; //ahora accesible Punto::y=y; //ahora accesible } }; class Punto{ protected: double x, y; //… };

12 Accesibilidad a clase Base en Derivación Pública
Acceso desde el exterior attr_publico Acceso desde el interior attr_protegido attr_privado Se hereda: El interfaz (parte pública) La implementación (por defecto) Acceso desde la clase derivada attr_protegido attr_publico Acceso desde el exterior attr_publico Acceso desde futuras derivaciones El status del estado y funciones miembro de Base no cambia

13 OTROS DETALLES DE LA DERIVACIÓN PÚBLICA EN C++

14 Cosas que NO se heredan Constructores y destructores
Se usan en el momento de la creación de una instancia de la clase derivada Operador asignación (operator =) sobrecargado Un problema relacionado es el del constructor copia Relaciones de amistad (calificador friend) Atributos estáticos (static)

15 Constructores y destructores
Las reglas son similares a las de construcción/destrucción de objetos miembro ya vistas, sólo que ahora el objeto miembro es la clase base heredada. Se llama primero al constructor de la clase base y luego al de la derivada Los destructores se llaman en orden inverso. class Punto{ double x, y; public: Punto(double x, double y): x(x), y(y) {cout<<"llamada a constructor de punto"<<endl;} ~Punto(){cout<<"llamada al destructor de punto"<<endl;} //… }; class Puntocol: public Punto{ char* color; public: Puntocol(double x, double y, const char* color):Punto(x, y){ //… cout<<"llamada al constructor de puntocol"<<endl;} ~Puntocol(){cout<<"llamada al destructor de puntocol"<<endl;} }; void main(){ Puntocol (0.0, 1.0, “azul”); }

16 TEST UNITARIO (“*.cpp”)
Constructor copia (1/2) Sea B la clase base y D la derivada Caso I: D NO tiene definido constructor copia (CC(D)) REGLA1. Se llama al CC(D) predet. para inicializar la parte de D REGLA II. Se llama al CC(B) (o en su defecto al CC(B) predet. ) para inicializar la parte de B DECLARACION ("cder.h”) #include "cbase.h" class CDer:public CBase{ int b; public: CDer(int n, int m):CBase(n),b(m){} void print(){cout<<a<<","<<b<<endl;}; }; DECLARACION ("cbase.h") class CBase{ protected: int a; public: CBase(int n):a(n){} CBase(const CBase& b){ cout<<"CC(B)"; this->a = b.a; } }; TEST UNITARIO (“*.cpp”) void main(){ CDer d1(3,6); CDer d2(d1); d2.print(); } Cuestión ¿Salida en pantalla ?

17 Conversión implícita DerBase
Constructor copia (2/2) Caso II : D tiene definido constructor copia (CC(D)) La responsabilidad recae completamente en CC(D) para la construcción REGLA I. Si CC(D) tiene información para B (p. ej. D::D(const D& b):B(b){…} ) se llama al constructor correspondiente de B REGLA II. Si CC(D) NO tiene información para B se llama al constructor de B SIN argumentos. (NO hay llamada al CC(B) predet.) class CDer:public CBase{ int b; public: CDer(int n, int m):CBase(n),b(m){} CDer(const CDer& d):CBase(d){ cout<<"CCD"; this->b=d.b; } void print(){cout<<a<<","<<b<<endl;}; }; class CBase{ protected: int a; public: CBase(int n):a(n){} CBase():a(0){cout<<"CB";} CBase(const CBase& b){ cout<<"CCB"; this->a=b.a; } }; Conversión implícita DerBase TEST UNITARIO (*.cpp) void main(){ CDer d1(3,6); CDer d2(d1); d2.print(); } Cuestión ¿Salida en pantalla ?

18 Operador asignación (=) (1/2)
Sean B la clase base y D la derivada: I. D no tiene sobrecargado el operador asignación Se llama al operador asignación predefinido (o sobrecargado si existe para B) para la parte de B y D II. D tiene sobrecargado el operador asignación La responsabilidad recae sobre dicho operador para asignar la parte de B NO se llama al operador asignación de B si no se hace la llamada explícitamente Las reglas son similares a las vistas para el constructor copia

19 Ejemplo (2/2) class Base { public:
Base(int initialValue = 0): x(initialValue) {} private: int x; }; class Derived: public Base { Derived(int initialValue): Base(initialValue), y(initialValue) {} Derived& operator=(const Derived& rhs); int y; Derived& Derived::operator=(const Derived& rhs){ if (this == &rhs) return *this; Base::operator=(rhs); y = rhs.y; //asignación sólo a la parte de Y return *this; }

20 Caso práctico: Jerarquía Nombre-Alumno
EJERCICIO Implementar en C++ esta jerarquía Notas: Implemente print() para la clase Alumno como método colaborativo Implemente constructor y constructor copia en toda la jerarquía

21 Solución parcial: operador asignación
class Nombre{ char *nombre; public: Nombre(char *nom); Nombre(const Nombre &nom); Nombre & operator = (const Nombre &nom){ delete [] nombre; nombre=new char[strlen(nom.nombre)+1]; strcpy(nombre,nom.nombre); return *this; } ~Nombre(){delete [] nombre;} void print(){cout<<nombre;} }; class Alumno:public Nombre{ int numero; public: Alumno(char *nom, int num); Alumno(const Alumno &al): Nombre(al),numero(al.numero){}; Alumno & operator = (const Alumno &al){ Nombre::operator = (al); numero=al.numero; return *this; } void print(); }; Cuestión* Implemente un caso de uso

22 Caso práctico: Jerarquía de Figuras
Ejercicio Implemente esta jerarquía con un test unitario apropiado

23 Otras nociones importantes
Conversión implícita de clase derivada a base (upcast) Enlace estático (static binding)

24 Comportamiento ES-UN: UPCAST (1/2)
Existe conversión implícita entre un objeto de una clase derivada y uno de su clase base (particulargeneral) Existe conversión implícita entre un puntero / referencia de una clase derivada a su clase base (particulargeneral) Enlace estático: Dicho objeto / puntero / referencia solo podrá acceder al estado y funciones de la clase (base) y NO a las del tipo original. class CDer:public CBase{ int b; public: CDer(int n, int m):CBase(n),b(m){} void print(){cout<<a<<","<<b<<endl;}; }; class CBase{ protected: int a; public: CBase(int n):a(n){} void print(){cout<<a<<endl;} }; void main() { CBase b(5); CDer d(1,10); b = d; //conversión b.print(); CBase* pb1=&b; CBase* pb2=&d; //conversión pb1print(); pb2print(); } Cuestión ¿Salida en pantalla?

25 Ejemplos-UPCAST (2/2) Cuestión
class CDer:public CBase{ int b; public: CDer(int n, int m):CBase(n),b(m){} void print(){ CBase::print(); cout<<b<<endl; }; class CBase{ private: int a; public: CBase(int n):a(n){} void print(){cout<<a<<endl;} }; Cuestión ¿Porqué se denomina “the slicing problem”? TEST UNITARIO B(*.cpp) void main(){ CBase *pb1=new CBase(1); CDer *pd1=new CDer(2,3); //I) CBase *pb2=pb1; CBase* pb3=pd1; pb2->print(); pb3->print(); //II) CDer* pd2 = static_cast<CDer*>(pb3); pd2->print(); } TEST UNITARIO A(*.cpp) void main(){ CBase b(2); CDer d(8,4); b.print(); d.print(); d=b; b=d; } DownCast explícito Cuestión* ¿Salida en pantalla A y B?

26 Ejercicio de examen Complete el siguiente código en C++ de la manera mas simple posible y de acuerdo con el test unitario class Nombre{ string nombre; public: Nombre(char *nom); Nombre(const Nombre &nom); Nombre& operator=(const Nombre& nom); void print_nombre(){cout<<nombre;} }; //TEST UNITARIO void main(){ Alumno al1("juan", 50837); Alumno al3("pedro", 40000); (al3=al1).print_alumno(); } class Alumno:public Nombre{ int numero; public: Alumno(char *nom, int num); Alumno(const Alumno &al); Alumno& operator=(const Alumno& rhs); void print_alumno(){print_nombre(); cout<<":"<<numero<<endl;}  };

27 Derivación pública (resumen)
REGLA 1: Conversión implícita UPCAST Se hereda el interfaz de la clase base Se hereda por defecto la implementación Significado: Relación ES-UN REGLA 2: El status de los miembros de la clase base se mantiene en la clase derivada Esta última regla sólo afecta a derivaciones posteriores (de la clase derivada) Nota: Las funciones amigas en una clase derivada tienen el mismo tipo de permiso (respecto a la clase base) que el resto de funciones miembro de la clase derivada

28 REDEFINICIÓN DE MÉTODOS (Overriding)
PROBLEMAS CON EL ENLACE ESTÁTICO (static binding)

29 Redefinición de métodos y atributos
Si un miembro (atributo o método) de la clase base se redefine — especializa — en la clase derivada su nombre queda oculto para las instancias de la clase derivada. El acceso desde la clase derivada a su clase base es posible sólo a través del operador scope (::). TEST UNITARIO (.cpp) void main(){ Puntocol p(5.0, 6.0, “azul”); p.ver(); p.Punto::ver(); } class Punto{ double x, y; public: Punto(double x, double y): x(x), y(y) {} void ver(){cout<<"("<<x<<","<<y<<")";} }; class Puntocol: public Punto{ char* color; public: Puntocol(double x, double y, const char* color):Punto(x, y){//…} ~Puntocol(){delete [] color;} void ver(){ //redefinición de función miembro Punto::ver(); cout<<" "<<color<<endl; } }; Cuestión I* Completar las funciones Cuestión II ¿Es x accesible en Puntocol?

30 Problemas del enlace estático
class Guerrero{ public: void pelear(){ //pelea por defecto cout<<"pelea de guerrero"<<endl; } }; class Mago:public Guerrero{ void pelear(){ cout<<"pelea de mago"<<endl; UPCAST: El enlace estático en la herencia hace que el mago pelee como un guerrero genérico dentro de cualquier función que, esperando a un guerrero, reciba a un mago.

31 OTRAS RELACIONES DE DERIVACIÓN

32 Índice Derivación privada Derivación protegida

33 Derivación privada class <clase Derivada> : private <clase Base> REGLA I*. NO hay conversión implícita UPCAST del compilador No se hereda el interfaz de la clase Base Significado: Es una relación ESTA-IMPLEMENTADO-POR o CONTIENE-A REGLA 2*. Todos los miembros de la clase base tienen status PRIVADO en la clase derivada. Base Derivada + attr1 private # attr2 - attr1 - attr2

34 Accesibilidad a clase Base en Derivación Privada
Acceso desde el exterior attr_publico Acceso desde el interior attr_protegido Se hereda: La implementación Acceso desde la clase derivada attr_protegido attr_publico Acceso desde el exterior En ningún caso Acceso desde futuras derivaciones El status del estado y funciones miembro de Base es PRIVADO

35 NO es una relación ES-UN
class Persona { ... }; class Alumno: private Persona { ... }; void baila (Persona & p); // las personas bailan void estudia (const Alumno & a); // los alumnos estudian Persona p; // p es una persona Alumno a; // a es un alumno baila(p); // correcto: p es una Persona baila(a); // ¿¿??? Cuestión ¿Pueden bailar los alumnos?

36 Acerca de Alumnos y sus nombres
CUESTION ¿La relación Nombre-Alumno puede modelarse con derivación privada? Justifique la respuesta EJERCICIO I. Implemente Nombre-Alumno como derivación privada II. Implemente Nombre-Alumno como Alumno con objeto miembro Nombre (“layering”). III. Comente acerca de las diferencias.

37 Acerca de Magos y Espadas
El MagoPequeño ve a Mago como un TODO debido a la derivación privada El cliente de MagoPequeño ve a Mago como un TODO debido a la derivación privada

38 Ejercicio A B Enumere todas las diferencias funcionales que encuentre entre estas dos arquitecturas Nota: Considere también el impacto en las sucesivas derivaciones de la clase Mago

39

40 Derivación protegida (protected)
class <clase derivada> : protected <clase Base> REGLA I*. NO hay conversión implícita UPCAST del compilador Idéntico comportamiento a la derivación privada REGLA 2*. Los miembros de la clase base protegidos y públicos pasan a status PROTEGIDO en la clase derivada Base Derivada + attr1 protected # attr2 # attr1

41 Accesibilidad a clase Base en Derivación Protegida
Acceso desde el exterior attr_publico Acceso desde el interior attr_protegido Se hereda: La implementación Acceso desde la clase derivada attr_protegido attr_publico Acceso desde el exterior En ningún caso Acceso desde futuras derivaciones attr_privado  privado (-) attr_protegido  protegido (#) attr_publico  protegido (#)

42 Acerca de Magos y Espadas
El cliente de MagoPequeño ve a Mago como un TODO debido a la derivación protegida de Mago. El MagoPequeño, sin embargo, tiene acceso a los atributos protegidos y públicos aguas arriba de Mago

43 Cuadro resumen tipos de derivación
Clase base Derivada pública Derivada protegida Derivada privada Status inicial Acceso definición Acceso usuario Nuevo status Nuevo status público S protegido N privado NOTA: El nuevo status de un atributo/función miembro en la clase derivada solo tiene relevancia a efectos de derivaciones futuras

44 Herencia múltiple

45 RESUMEN Derivación pública, privada y protegida Overriding (redefinición) Static bind (enlace estático) Herencia múltiple Ejemplos ¿PREGUNTAS?


Descargar ppt "Pablo San Segundo (C-206) pablo.sansegundo@upm.es Herencia Pablo San Segundo (C-206) pablo.sansegundo@upm.es."

Presentaciones similares


Anuncios Google