Iterazione polimorfica
Fa parte della sezione Programmazione orientata agli oggetti del percorso C di Coddy. Lezione 42 di 61.
Hai imparato a creare interfacce e a implementarle con diverse funzioni concrete. Il vero vantaggio arriva quando puoi trattare in modo uniforme una raccolta di oggetti diversi: scorrerli e chiamare lo stesso puntatore a funzione su ciascuno, indipendentemente dal comportamento specifico a cui è collegato.
Immagina di avere un array di struct Action, ciascuna con la propria funzione execute assegnata:
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"); }Puoi creare un array di queste azioni, ciascuna collegata a una funzione diversa, quindi scorrerle con un semplice ciclo 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;
}Il ciclo non sa né gli importa cosa fa internamente ciascuna azione. Si limita a chiamare execute() su ogni elemento.
Questo è il polimorfismo in azione: lo stesso codice gestisce oggetti con comportamenti completamente diversi. Per aggiungere un nuovo tipo di azione non occorre modificare la logica di iterazione; basta aggiungere un altro elemento all'array.
Sfida
FacileCostruiamo un sistema di gestione Task che dimostri l’iterazione polimorfica: elaborare una raccolta di oggetti che condividono un’interfaccia comune ma eseguono comportamenti diversi.
Organizzerai il codice in tre file:
task.h: definisci qui l’interfaccia delle attività. Crea un tipo di puntatore a funzione chiamatoTaskFuncche non accetta parametri e non restituisce nulla. Poi definisci una structTaskcontenente unname(unconst char*) e un puntatore a funzionerundi tipoTaskFunc.task.c: implementa tre diverse funzioni per le attività, che rappresentano diversi tipi di lavoro:backup_task: stampaBacking up data...cleanup_task: stampaCleaning up files...report_task: stampaGenerating report...
main.c: metti insieme qui tutti gli elementi. Crea un array di structTask, ciascuna associata a una diversa funzione per le attività. Poi scorri l’array ed esegui ogni attività in modo polimorfico; per ciascuna attività, stampa il suo nome seguito dalla chiamata alla sua funzionerun.
Il programma riceverà un solo input: il numero di attività da eseguire (1, 2 o 3).
Crea un array contenente esattamente tre attività in questo ordine: un’attività di backup chiamata Backup, un’attività di pulizia chiamata Cleanup e un’attività di report chiamata Report. In base al numero ricevuto in input, scorri solo quel numero di attività a partire dall’inizio dell’array.
Per ogni attività durante l’iterazione, stampa il nome dell’attività seguito da due punti e uno spazio, poi chiama la sua funzione run.
Esempio di output quando l’input è 2:
Backup: Backing up data...
Cleanup: Cleaning up files...Esempio di output quando l’input è 3:
Backup: Backing up data...
Cleanup: Cleaning up files...
Report: Generating report...L’idea fondamentale è che il ciclo non deve sapere cosa fa ciascuna attività. Si limita a stampare il nome e a chiamare run() su ciascun elemento. Lo stesso codice di iterazione gestisce uniformemente tutti i tipi di attività. Ricordati di usare le include guard nel file header.
Provalo tu
#include <stdio.h>
#include "task.h"
// Dichiara le funzioni delle attività implementate in 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 di 3 strutture Task in questo ordine:
// 1. Attività di backup chiamata "Backup" che usa backup_task
// 2. Attività di pulizia chiamata "Cleanup" che usa cleanup_task
// 3. Attività di report chiamata "Report" che usa report_task
// TODO: Scorri 'count' attività dell'array
// Per ogni attività, stampa: "<name>: " poi chiama la sua funzione run
return 0;
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Basi di programmazione modulare
File di intestazioneGuardie di inclusioneFile sorgenteFunzioni staticheRipasso: calcolatrice modulare4Incapsulamento
Il concetto di puntatori opachiDefinire struct opacheGetter e setterLa convalida nei setterRiepilogo: scatola segreta2Oggetti e metodi
Le struct come oggettiIl puntatore 'Self'Correttezza constPuntatore o valoreMetodi di supportoRiepilogo: gestore di punti5Progetto: Conto bancario semplice
Configurazione del progettoImplementazione del conto8Polimorfismo
Puntatori a funzione nelle structSimulare i metodiIl concetto di interfacciaImplementare le interfacceIterazione polimorficaRiepilogo: Greeter11Pattern di progettazione in C
Pattern SingletonPattern FactoryPattern IteratorRiepilogo: Factory di Logger3Ciclo di vita degli oggetti
Pattern del costruttorePattern del distruttoreInizializzazione sullo stackCopia profondaRiepilogo: wrapper di stringhe6Ereditarietà tramite composizione
Incorporamento delle structLa regola del primo membroAccesso ai membri della classe baseUpcastingRiepilogo: gerarchia di forme9Progetto: Disegnatore di forme
Panoramica del progettoImplementazione del cerchioImplementazione del rettangoloUtilizzo polimorficoContenitore di formeEsercitati da solo: Compilatore C online