5.1 Importancia de la herencia en la POO
El mecanismo de herencia es uno de los pilares fundamentales en los que se basa la programación orientada a objetos. Es un mecanismo que permite definir nuevas clases a partir de otras ya definidas de modo que si en la definición de una clase indicamos que ésta deriva de otra, entonces la primera -a la que se le suele llamar clase hija- será tratada por el compilador automáticamente como si su definición incluyese la definición de la segunda –a la que se le suele llamar clase padre o clase base.
5.2 Jerarquía de herencia
La Jerarquía es una propiedad que permite la ordenación de las abstracciones
Las jerarquías de herencia son más fáciles de implementar que de diseñar, por lo que es arriesgado comenzar a codificar antes de identificar claramente las necesidades. La corrección de errores de diseño en una jerarquía de clases tras la implementación puede requerir cambios que deshabilitan las aplicaciones existentes. En esta sección se explican consideraciones del diseño de jerarquía de herencia y se proporciona información que ayuda a evitar estos errores.
En una jerarquía de herencia, la regla de dominio se emplea para resolver ambigüedades. Si una clase base y
una clase derivada tienen un miembro con el mismo nombre, el que esté en la clase derivada es el dominante.
5.2.1 Conceptos de Herencia simple y múltiple
Herencia Simple La herencia en C++ es un mecanismo de abstracción creado para poder facilitar, y mejorar el diseño de las clases de un programa. Con ella se pueden crear nuevas clases a partir de clases ya hechas, siempre y cuando tengan un tipo de relación especial. En la herencia, las clases derivadas “heredan” los datos y las funciones miembro de las clases base, pudiendo las clases derivadas redefinir estos comportamientos (polimorfismo) y añadir comportamientos nuevos propios de las clases derivadas.
5.2.2 Principios generales de diseño de jerarquías.
Las jerarquías se definen desde lo general a lo específico. Defina las clases en cada nivel de una jerarquía de herencia de la forma más genérica posible. Las clases derivadas pueden heredar, reutilizar y extender métodos de clases base.
Defina los tipos de datos y el almacenamiento con generosidad a fin de evitar cambios difíciles posteriormente. Por ejemplo, podría considerar el uso de una variable de tipo Long aunque los datos actuales sólo requieran una variable estándar Integer.
Exponga sólo los elementos que las clases derivadas necesiten. Los campos y métodos Private reducen los conflictos de denominación y protegen a otros usuarios del uso de elementos que pueden necesitar cambios posteriormente
Los miembros que sólo sean necesarios para las clases derivadas deben marcarse como Protected. Esto garantiza que sólo las clases derivadas dependen de estos miembros y facilita la actualización de estos miembros durante el desarrollo.
Asegúrese de que los métodos de clase base no dependen de miembros Overridable cuya funcionalidad pueden cambiar las clases herederas. Existen dos tipos de jerarquizar: La primera consiste en derivar una clase de otra, es el caso mas habitual y se llama “Herencia”.
5.2.3 Especificadores de acceso a jerarquía de clases.
Los especificadores de acceso a la clase base definen los posibles tipos de derivación: public, private y protected. El tipo de acceso a la clase base especifica cómo recibirá la clase derivada a los miembros de clase base. Si no se especifica un acceso a la clase base, C++ supone que su tipo de herencia es privado. Los accesos a la clase base pueden ser:
public: Los miembros públicos de la clase base son miembros públicos de la clase derivada. Los miembros protegidos de la clase base son miembros protegidos de la clase derivada. Los miembros privados de la case base permanecen privados a la clase derivada.
private: Todos los miembros públicos y protegidos de la clase base son miembros privados de la clase derivada. Los miembros privados de la clase base permanecen privados a la clase derivada.
protected: todos los miembros públicos y protegidos de la clase base son miembros protegidos de la clase derivada. Los miembros privados de la clase base permanecen privados a la clase derivada.
5.3 Definición de una clase base
La clase base define todas las cualidades que serán comunes a cualquier clase derivada. Otro punto importante es el acceso a la clase base. El acceso a la clase base pude tomar 3 valores, public, private y protected.
Si el acceso es public, todos los atributos de la clase base son públicos para la derivada.
Si el acceso es private, los datos son privados para la clase base la derivada no tiene acceso.
Si el acceso es protected, datos privados para la base y derivada tiene acceso, el resto sin acceso.
5.4 Definición de una clase derivada
En la clase derivada se define una función que tiene el mismo nombre y los mismos parámetros que la de la clase base. Se dice que redefinimos la función mostrar en la clase derivada. La función miembro mostrar de la clase derivada VentanaTitulo hace una llamada a la función mostrar de la clase base Ventana, mediante
Una clase derivada hereda la función miembro de su clase base. Esto significa que se hereda la capacidad para llamar a funciones miembro de la clase base en los objetos de la clase derivada.
Los siguientes elementos de la clase no se heredan:
- Constructores
- Destructores
- Funciones amigas
- Funciones estáticas de la clase
- Datos estáticos de la clase
- Operador de asignación sobrecargado
5.4.1 Constructores y destructores de clases derivadas
El caso de los constructores es un poco especial. Se ejecutan en orden descendente, es decir primero se realiza el constructor de la clase base y luego el de las derivadas. En las destructoras ocurre en orden inverso, primero el de las derivadas y luego el de la base.
Destructores en clases derivadas Cuando remueve de la memoria un objeto de una clase derivada, el recolector de basura invoca al destructor del objeto. Esto inicia una cadena de invocaciones a destructores, en donde el destructor de la clase derivada y los destructores de las clases bases directas e indirectas se ejecutan en orden inverso al que se ejecutaron los constructores, esto es, primero se ejecuta el destructor de la clase derivada y al final se ejecuta el destructor de la clase base ubicada en el nivel superior de la jerarquía. La ejecución de los destructores debe liberar todos los recursos que el objeto adquirió, antes de que el recolector de basura reclame la memoria de ese objeto. Cuando el recolector de basura invoca al destructor de un objeto de una clase derivada, ese destructor realiza su tarea y después invoca al destructor de la clase base. El proceso se repite hasta que se invoca al destructor de la clase Object.
5.4.2 Conversión implícita de objetos de clase derivada a objeto de clase base
La programación orientada a objetos extiende los tipos abstractos de datos permitiendo relaciones tipo-subtipo. Esto es alcanzado a través de un mecanismo denominado herencia. Más que reimplementar características compartidas, una clase puede heredar datos y funciones miembros de otras clases. En C++, este mecanismo es implementado a través de la derivación de clases.
5.5 Herencia múltiple
Es una propiedad que permite que los objetos sean creados a partir de otros ya existentes, obteniendo características (métodos y atributos) similares a los ya existentes. Es la relación entre una clase general y otra clase más específica. Es un mecanismo que nos permite crear clases derivadas a partir de clase base, nos permite compartir automáticamente métodos y datos entre clases, subclases y objetos.
Existen dos métodos en los que una clase derivada puede heredar más de una clase base. El primero, en el que una clase derivada puede ser usada como la clase base de otra clase derivada, creándose una jerarquía de clases. El segundo, es que una clase derivada puede heredar directamente más de una clase base. En esta situación se combinan dos o más clases base para facilitar la creación de la clase derivada.