Iteración polimórfica
Parte de la sección Programación Orientada a Objetos del Journey de C de Coddy. Lección 42 de 61.
Has aprendido a crear interfaces e implementarlas con diferentes funciones concretas. La verdadera recompensa llega cuando puedes tratar de manera uniforme una colección de objetos diferentes: iterar por ellos y llamar al mismo puntero a función en cada uno, independientemente del comportamiento específico que esté conectado.
Imagina que tienes un array de estructuras Action, cada una con su propia función execute asignada:
typedef void (*ExecuteFunc)(void);
typedef struct {
const char* name;
ExecuteFunc execute;
} Action;
void jump(void) { printf("Jumping!\n"); }
void run(void) { printf("Running!\n"); }
void rest(void) { printf("Resting...\n"); }Puedes crear un array de estas acciones, cada una conectada a una función diferente, después recorrerlas con un simple bucle for:
int main() {
Action actions[3] = {
{ "Jump", jump },
{ "Run", run },
{ "Rest", rest }
};
for (int i = 0; i < 3; i++) {
printf("%s: ", actions[i].name);
actions[i].execute();
}
return 0;
}El bucle no sabe ni le importa qué hace cada acción internamente. Simplemente llama a execute() en cada elemento.
Esto es el polimorfismo en acción: el mismo código gestiona objetos con comportamientos completamente diferentes. Añadir un nuevo tipo de acción no requiere cambios en la lógica de iteración; solo tienes que añadir otro elemento al array.
Desafío
FácilConstruyamos un sistema de gestión de Task que demuestre la iteración polimórfica: procesar una colección de objetos que comparten una interfaz común, pero ejecutan comportamientos diferentes.
Organizarás tu código en tres archivos:
task.h: Define aquí la interfaz de tu tarea. Crea un tipo de puntero a función llamadoTaskFuncque no acepte parámetros ni devuelva nada. Después, define una estructuraTaskque contenga unname(unconst char*) y un puntero a funciónrunde tipoTaskFunc.task.c: Implementa tres funciones de tarea diferentes que representen distintos tipos de trabajo:backup_task: imprimeBacking up data...cleanup_task: imprimeCleaning up files...report_task: imprimeGenerating report...
main.c: Reúne todo aquí. Crea un arreglo de estructurasTask, cada una vinculada a una función de tarea diferente. Después, recorre el arreglo y ejecuta cada tarea polimórficamente; para cada tarea, imprime su nombre y luego llama a su funciónrun.
Tu programa recibirá una única entrada: el número de tareas que se ejecutarán (1, 2 o 3).
Crea un arreglo que contenga exactamente tres tareas en este orden: una tarea de respaldo llamada Backup, una tarea de limpieza llamada Cleanup y una tarea de informe llamada Report. Según la cantidad indicada en la entrada, recorre solo esa cantidad de tareas desde el principio del arreglo.
Para cada tarea de la iteración, imprime el nombre de la tarea seguido de dos puntos y un espacio; después, llama a su función run.
Salida de ejemplo cuando la entrada es 2:
Backup: Backing up data...
Cleanup: Cleaning up files...Salida de ejemplo cuando la entrada es 3:
Backup: Backing up data...
Cleanup: Cleaning up files...
Report: Generating report...La idea clave es que tu bucle no necesita saber qué hace cada tarea. Simplemente imprime el nombre y llama a run() en cada elemento. El mismo código de iteración gestiona todos los tipos de tareas de manera uniforme. Recuerda usar guardas de inclusión en tu archivo de cabecera.
Pruébalo tú mismo
#include <stdio.h>
#include "task.h"
// Declara las funciones de tarea implementadas en task.c
void backup_task(void);
void cleanup_task(void);
void report_task(void);
int main() {
int count;
scanf("%d", &count);
// TODO: Crea un array de 3 structs Task en este orden:
// 1. Tarea de respaldo llamada "Backup" usando backup_task
// 2. Tarea de limpieza llamada "Cleanup" usando cleanup_task
// 3. Tarea de informe llamada "Report" usando report_task
// TODO: Itera a través de 'count' tareas del array
// Para cada tarea, imprime: "<name>: " luego llama a su función run
return 0;
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de programación modular
Archivos de cabeceraGuardas de inclusiónArchivos fuenteFunciones estáticasRepaso: Calculadora modular4Encapsulamiento
Concepto de punteros opacosDefinición de structs opacosGetters y SettersValidación en settersResumen: Caja secreta7Punteros a funciones
Declaración de punteros a funcionesLlamada a punteros a funcionesTypedef para punteros a funcionesPasar funciones como argumentosRepaso: Dispatch de calculadora10Contenedores genéricos
Repaso de punteros voidWrapper genéricoSwap genéricoComparación genéricaRepaso: Array genérico2Objetos y métodos
Structs como objetosEl puntero 'Self'Const CorrectnessPuntero vs. ValorMétodos auxiliaresResumen: Point Manager5Proyecto: Cuenta bancaria simple
Configuración del proyectoImplementación de la cuenta8Polimorfismo
Punteros a funciones en estructurasSimulando métodosEl concepto de interfazImplementando interfacesIteración polimórficaResumen: Greeter3Ciclo de vida de los objetos
Patrón ConstructorPatrón DestructorInicialización en StackCopia profundaResumen: String Wrapper6Herencia mediante composición
Incrustación de StructsLa regla del primer miembroAcceso a miembros padreUpcastingResumen: Jerarquía de formas9Proyecto: Dibujador de figuras
Descripción general del proyectoImplementación del círculoImplementación del rectánguloUso polimórficoContenedor de figurasPractica por tu cuenta: Compilador de C online