Café y Código
⚡ C++ Avanzado· Lección 10

10. Pilares de POO: Herencia y Polimorfismo Dinámico 🏛️⚡

Descubre los superpoderes arquitectónicos de C++: cómo videojuegos como World of Warcraft o Cyberpunk gestionan cientos de entidades distintas con una interfaz común.

1. Herencia: Reutilizar sin Duplicar Código

La herencia permite crear una clase derivada (hija) que absorbe todos los atributos y métodos de una clase base (padre), añadiendo sus propias especializaciones.

herencia_personajes.cpp
CPP
1#include <iostream>
2#include <string>
3
4// Clase Base
5class Personaje {
6protected:
7 std::string nombre;
8 int salud;
9
10public:
11 Personaje(std::string n, int s) : nombre(n), salud(s) {}
12
13 void recibirDanio(int danio) {
14 salud -= danio;
15 std::cout << nombre << " recibió " << danio << " de daño. Salud restante: " << salud << "\n";
16 }
17};
18
19// Clase Derivada (Hereda de Personaje)
20class Mago : public Personaje {
21private:
22 int mana;
23
24public:
25 Mago(std::string n, int s, int m) : Personaje(n, s), mana(m) {}
26
27 void lanzarHechizo() {
28 std::cout << nombre << " lanza Bola de Fuego consumiendo 20 de mana!\n";
29 mana -= 20;
30 }
31};
💡 ¿Por qué usamos protected?

Si los atributos fueran private en Personaje, ni siquiera la clase hija Mago podría acceder a nombre. Con protected, quedan protegidos del mundo exterior pero accesibles para sus clases hijas.

2. Polimorfismo Dinámico: La Magia de virtual y override

El polimorfismo te permite tratar a objetos diferentes a través de un mismo puntero a la clase base, ejecutando la versión especializada de cada uno en tiempo de ejecución.

🔮 ¿Por qué es obligatoria la palabra clave virtual?

Por defecto, C++ enlaza las llamadas a métodos en tiempo de compilación según el tipo del puntero. Al marcar una función como virtual, C++ activa la vtable (tabla de métodos virtuales), averiguando el tipo real del objeto en tiempo de ejecución.

polimorfismo_videojuego.cpp
CPP
1#include <iostream>
2#include <vector>
3
4class Enemigo {
5public:
6 virtual void atacar() const {
7 std::cout << "Ataque genérico del enemigo.\n";
8 }
9 // Destructor virtual obligatorio para liberar memoria limpia:
10 virtual ~Enemigo() = default;
11};
12
13class Dragon : public Enemigo {
14public:
15 void atacar() const override {
16 std::cout << "¡El Dragón escupe fuego devastador! 🔥\n";
17 }
18};
19
20class Zombie : public Enemigo {
21public:
22 void atacar() const override {
23 std::cout << "El Zombie muerde al jugador... 🧟\n";
24 }
25};
26
27int main() {
28 // Vector polimórfico de punteros a la base:
29 std::vector<Enemigo*> horda;
30 horda.push_back(new Dragon());
31 horda.push_back(new Zombie());
32
33 // El bucle principal no sabe qué criatura es, solo sabe que puede atacar:
34 for (Enemigo* e : horda) {
35 e->atacar(); // Ejecuta el ataque correcto de cada criatura
36 }
37
38 // Limpieza de memoria:
39 for (Enemigo* e : horda) delete e;
40 return 0;
41}

3. ⚠️ El Destructor Virtual: Previniendo Fugas de Memoria

Si eliminas un objeto derivado a través de un puntero a la clase base (delete e;), y la clase base no tiene un destructor virtual, ¡solo se ejecutará el destructor de la base y la memoria de la clase hija quedará filtrada en la RAM!

virtual ~ClaseBase() = default; // Agrega esto siempre a tus clases base

Ejercicio de Cierre del Curso

Diseña una clase base abstracta Figura con un método virtual puro virtual double calcularArea() const = 0;. Implementa dos clases derivadas: Rectangulo (ancho, alto) y Circulo (radio). Crea un vector de punteros a Figura y muestra el área de cada figura en un bucle polimórfico.

Ver solución completa
CPP
1#include <iostream>
2#include <vector>
3
4class Figura {
5public:
6 virtual double calcularArea() const = 0; // Virtual pura
7 virtual ~Figura() = default;
8};
9
10class Rectangulo : public Figura {
11private:
12 double ancho, alto;
13public:
14 Rectangulo(double a, double h) : ancho(a), alto(h) {}
15 double calcularArea() const override { return ancho * alto; }
16};
17
18class Circulo : public Figura {
19private:
20 double radio;
21public:
22 Circulo(double r) : radio(r) {}
23 double calcularArea() const override { return 3.14159 * radio * radio; }
24};
25
26int main() {
27 std::vector<Figura*> figuras = {
28 new Rectangulo(4.0, 5.0),
29 new Circulo(3.0)
30 };
31
32 for (Figura* f : figuras) {
33 std::cout << "Área de figura: " << f->calcularArea() << "\n";
34 delete f;
35 }
36 return 0;
37}
Evaluación Final del Curso

Comprueba lo que Has Aprendido 🧠

Valida tu dominio de herencia, polimorfismo dinámico, virtual y destructores.

Dato curioso: C++ apareció en 1985; Bjarne Stroustrup en Bell Labs. Wikipedia

Ko-fi
Donaciones
Apoyá cafeycodigo con un café en Ko-fi. Colaboradores: insignia, muro y zona exclusiva.