Want to create interactive content? It’s easy in Genially!

Get started free

POO - 3.4

susana.gonzalez

Created on November 9, 2023

Start designing with a free template

Discover more than 1500 professional designs like these:

Momentum: Employee Introduction Presentation

Momentum: Onboarding Presentation

Startup Presentation

Black and White Presentation

Marketing Presentation

Dynamic Visual Presentation

Corporate Christmas Presentation

Transcript

3.4 Otros procesos en la herencia

3.4.1 Reutilización de miembros heredados.

Cuando hablamos de reutilización de código, nos referimos al conjunto de comportamientos y técnicas que permiten usar parte o la totalidad de un programa existente en la construcción de otro. Esto significa aprovechar el trabajo previo, ahorrar tiempo y reducir redundancias. La forma más sencilla de reutilizar código es copiarlo desde un programa anterior al que estamos desarrollando. Sin embargo, mantener múltiples copias de código puede volverse complicado, por lo que generalmente eliminamos redundancias colocando el código reutilizable en un único lugar y llamándolo desde diferentes programas. Este proceso se llama abstracción y es claramente visible en las bibliotecas de software, que agrupan operaciones comunes para facilitar el desarrollo de nuevos programas. Para que el código existente sea reutilizable, debe definir alguna forma de comunicación o interfaz, que puede lograrse mediante llamadas a subrutinas, objetos o clases. Como mencionamos antes, una clase hija puede agregar sus propios atributos y métodos, pero también puede reemplazar u ocultar los heredados. Esto se puede hacer de varias maneras (García-Beltrán y Arranz, s.f.):

Lorem ipsum dolor sit amet consectetuer

Lorem ipsum dolor sit amet consectetuer

1990

2010

3.4.2 Referencia al objeto de la clase base.

Otro de los procesos que tiene la herencia, es la capacidad de hacer referencia y acceder a los miembros (métodos y atributos) de la clase padre desde una clase hija. Esta referencia permite a la clase hija usar y, en algunos casos, cambiar el comportamiento heredado de la clase padre. Cuando una clase hija se crea a partir de una clase padre, la referencia al objeto de la clase base (clase padre), permite el acceso a los miembros de esa clase mediante el uso de ciertos mecanismos proporcionados por el lenguaje de programación, como la palabra clave super en algunos lenguajes. Imagina que ClaseBase tiene un método llamado hacerAlgo(), y en ClaseDerivada quieres agregar algo más a ese método, pero sin perder lo que ya hace ClaseBase. Usar super en C++ (aunque no es una palabra clave, sino una convención), te permite llamar al método de la clase padre desde la clase hija y luego agregar tu propio código.

En este ejemplo, ClaseDerivada hereda de ClaseBase y tiene su propio método hacerAlgo(). Dentro de ese método, ClaseBase::hacerAlgo() se llama primero para ejecutar el código de la Clase Padre, y luego se agrega el código adicional de la Clase Hija. Esto permite extender el comportamiento sin perder la funcionalidad de la Clase Padre. Si te interesa observar otro ejemplo, pero ahora con el lenguaje Java, te invito a revisar el siguiente video a partir del minuto 2:50.

Video 5. Jesús Ríos. (12 de marzo de 2021). 3 4 Referencia al objeto de la clase base | Programación Orientada a Objetos [Video]. YouTube.

Espero que hayas realizado tus anotaciones.

3.4.3 Constructores y destructores en clases derivadas.

Hasta este momento, hemos trabajado entendiendo la importancia de reutilizar y referenciar las clases. Ahora nos toca explorar la implementación de constructores y destructores en el contexto de clase derivada (clase hija). Recordemos que un constructor es un método especial que se ejecuta automáticamente cuando se crea un objeto para contar con una inicialización eficiente y preparar al objeto para su uso. Cuando utilizamos herencia, las clases hijas no solo pueden tener sus propios constructores, sino que también pueden llamar al constructor de la clase padre para asegurar una inicialización completa y coherente. Un ejemplo de esto lo podemos observar en el siguiente código:

Por otro lado, el destructor entra en acción cuando un objeto se destruye, permitiendo la liberación ordenada de recursos. En clases hijas, el destructor de la clase padre se ejecuta automáticamente después del destructor de la clase hija, asegurando una liberación adecuada de recursos en toda la jerarquía de herencia. El destructor de una clase padre no es heredado por sus clases hijas. En cuanto a cómo se destruyen los objetos de las clases hijas, éstas se llevan a cabo en el orden inverso a como son construidos. Esto es: primeramente, se ejecuta el cuerpo del destructor de la clase hija, después son llamados los destructores para sus miembros y por último se ejecuta el destructor de la clase padre. Como los destructores no pasan argumentos, no requieren una sintaxis especial (Ceballos Sierra, 2015, pág. 300). Un ejemplo de esto lo podemos observar en el siguiente código:

3.4.4 Redefinición de métodos en clases derivadas.

Ya estando en la recta final de esta unidad, nos adentraremos en la redefinición de métodos en clases derivadas, por lo que no olvides anotar todas tus dudas para que puedas trabajarlas con tu asesor. Este último proceso de la herencia se refiere a la capacidad de una clase hija de proporcionar su propia implementación de un método que ya está definido en la clase padre. En otras palabras, la clase hija ofrece una versión específica de un método que ya existe en la clase padre, y esta versión específica es la que se ejecutará cuando el método se llame en un objeto de la clase hija. Cuando una clase hija redefine un método de la clase padre, se busca proporcionar una implementación más adecuada o específica para esa clase en particular. Este proceso es fundamental para el polimorfismo, que permite a diferentes clases compartir un nombre de método común, pero con comportamientos específicos para cada clase. Analicemos el siguiente código:

En este ejemplo, la clase padre Animal tiene un método hacerSonido() que imprime un sonido genérico de un animal. Las clases hijas Perro y Gato redefinen este método para proporcionar su propio sonido específico para cada tipo de animal. Cuando llamamos a hacerSonido() en un objeto de la clase hija, se ejecuta la versión específica de ese objeto. Te invito a revisar el siguiente documento (de la página 53 a la 65) donde podrás observar otro ejemplo. Recuerda realizar las anotaciones correspondientes.

Lectura obligatoria 2. Aransay Azofra, J. M. (s.f.). Tema 2. Relaciones entre clases. Herencia entre clases [Archivo PDF]. Universidad de La Rioja. https://www.unirioja.es/cu/jearansa/0910/archivos/EIPR_Tema02.pdf

Por lo anterior, hay que mencionar que la redefinición de métodos en clases hijas es fundamental para aprovechar el polimorfismo y permitir una mayor flexibilidad y extensibilidad en el diseño de sistemas orientados a objetos. Con este tema hemos finalizado la Unidad 3, esperando que haya sido emocionante e interesante. Es el momento de realizar la actividad asignada. ¡Éxito!

Ejemplo en C++: #include <iostream> // Definición de la Clase padre class ClaseBase { public: void hacerAlgo() { std::cout << "Haciendo algo en la Clase Base" << std::endl; } }; // Definición de la Clase hija class ClaseDerivada : public ClaseBase { public: void hacerAlgo() { ClaseBase::hacerAlgo(); // Llamada al método de la Clase Base std::cout << "Añadiendo algo en la Clase Derivada" << std::endl; } }; int main() { // Crear una instancia de la Clase hija ClaseDerivada objetoDerivado; // Llamar al método de la Clase hija objetoDerivado.hacerAlgo(); return 0; } }

Declarar un nuevo atributo con el mismo identificador que uno heredado, ocultando este último. Sin embargo, esta técnica no se recomienda.

Declarar un nuevo método de clase con la misma estructura que el de la clase padre, ocultando así el original. Ten en cuenta que los métodos de clase o estáticos (declarados como static) no pueden ser redefinidos.

#include <iostream> // Clase Padre con Destructor class ClaseBase { public: ~ClaseBase() { std::cout << "Destructor de ClaseBase" << std::endl; } }; // Clase Hija con Destructor class ClaseDerivada : public ClaseBase { public: ~ClaseDerivada() { std::cout << "Destructor de ClaseDerivada" << std::endl; } }; int main() { ClaseDerivada* objetoDerivado = new ClaseDerivada(); delete objetoDerivado; // Salida: Destructor de ClaseDerivada, Destructor de ClaseBase return 0; }

#include <iostream> // Clase Padrecon Constructor class ClaseBase { public: ClaseBase() { std::cout << "Constructor de ClaseBase" << std::endl; } }; // Clase Hija con Constructor class ClaseDerivada : public ClaseBase { public: ClaseDerivada() { std::cout << "Constructor de ClaseDerivada" << std::endl; } }; int main() { ClaseDerivada objetoDerivado; // Salida: Constructor de ClaseBase, Constructor de ClaseDerivada return 0; }

Declarar un nuevo método de instancia con la misma estructura que el de la clase padre, sobreescribiéndolo. En otras palabras, métodos adicionales en la clase hija con el mismo nombre, tipo de dato devuelto y número y tipo de parámetros sustituyen a los heredados.

Un método declarado con el modificador final tampoco puede ser redefinido por una clase hija.

En general, puedes acceder a los métodos de la clase padre que han sido redefinidos utilizando la palabra reservada 'super', seguida del identificador del método. Sin embargo, este mecanismo solo permite acceder al método de la clase inmediatamente superior en la jerarquía.

#include <iostream> // Clase padre class Animal { public: void hacerSonido() { std::cout << "Sonido genérico de un animal" << std::endl; } }; // Clase hija class Perro : public Animal { public: void hacerSonido() { std::cout << "Ladrar como un perro" << std::endl; } }; // Clase hija class Gato : public Animal { public: void hacerSonido() { std::cout << "Maullar como un gato" << std::endl; } }; int main() { Animal animal; Perro perro; Gato gato; // Llamadas a los métodos hacerSonido de las diferentes clases animal.hacerSonido(); // Salida: Sonido genérico de un animal perro.hacerSonido(); // Salida: Ladrar como un perro gato.hacerSonido(); // Salida: Maullar como un gato return 0; }

Puedes declarar un constructor en la subclase (clase hija) que llame al de la superclase (clase padre) de forma implícita o mediante la palabra reservada 'super'.