Herencia en C con composición: ejercicio resuelto
Si buscas herencia en C, el enfoque práctico es simularla con composición y punteros a función, porque C no incluye herencia nativa.
Este patrón te permite modelar jerarquías simples y comportamiento dinámico sin salir de C puro.
Enunciado
Modela una jerarquía básica:
- tipo base
Animalcon nombre y funciónhablar, - tipo
Perroy tipoGatoque “extienden” aAnimalpor composición, - recorrido de un array de
Animal*para ejecutar comportamiento polimórfico.
Solución en C
#include <stdio.h>
typedef struct Animal Animal;
typedef void (*HablarFn)(const Animal *);
struct Animal {
const char *nombre;
HablarFn hablar;
};
typedef struct {
Animal base;
int energia;
} Perro;
typedef struct {
Animal base;
int vidas;
} Gato;
void perro_hablar(const Animal *a) {
const Perro *p = (const Perro *)a;
printf("Perro %s: guau (energía=%d)\n", p->base.nombre, p->energia);
}
void gato_hablar(const Animal *a) {
const Gato *g = (const Gato *)a;
printf("Gato %s: miau (vidas=%d)\n", g->base.nombre, g->vidas);
}
Perro perro_crear(const char *nombre, int energia) {
Perro p;
p.base.nombre = nombre;
p.base.hablar = perro_hablar;
p.energia = energia;
return p;
}
Gato gato_crear(const char *nombre, int vidas) {
Gato g;
g.base.nombre = nombre;
g.base.hablar = gato_hablar;
g.vidas = vidas;
return g;
}
int main(void) {
Perro p = perro_crear("Toby", 80);
Gato g = gato_crear("Misu", 9);
Animal *grupo[] = {(Animal *)&p, (Animal *)&g};
int n = (int)(sizeof(grupo) / sizeof(grupo[0]));
for (int i = 0; i < n; i++) {
grupo[i]->hablar(grupo[i]);
}
return 0;
}Resultado esperado
Perro Toby: guau (energía=80)
Gato Misu: miau (vidas=9)Errores frecuentes
- Copiar solo el tipo base en vez de trabajar con punteros al tipo compuesto.
- Olvidar inicializar el puntero a función y provocar fallo en tiempo de ejecución.
- Hacer cast de tipos no compatibles.
- Intentar replicar herencia compleja de POO clásica en C sin necesidad.
Aplicación práctica
Este patrón se usa para:
- diseñar motores y librerías con callbacks,
- modelar plugins y controladores con interfaz común,
- reducir acoplamiento entre módulos.
Es una habilidad útil para C de sistemas y código mantenible.
Siguiente ejercicio recomendado
- Clases en C con struct: ejercicio resuelto de diseño modular
- Struct en C: ejercicio resuelto con arrays de estructuras
- Puntero a puntero en C: ejercicio resuelto con cambio de referencia
- Todos los ejercicios de C
Práctica guiada y siguiente paso
Si quieres una ruta completa con progresión real de dificultad:
FAQ
¿La herencia en C existe de forma nativa?
No. En C se simula con composición, punteros y funciones para compartir interfaz y comportamiento.
¿Cuándo merece la pena usar punteros a función?
Cuando necesitas comportamiento intercambiable en tiempo de ejecución, por ejemplo estrategias, callbacks o controladores.
¿Este patrón sustituye por completo a la POO?
No. C no ofrece todas las abstracciones de POO, pero este enfoque cubre muchos casos prácticos de diseño modular.