Puntatori a funzione nelle struct
Fa parte della sezione Programmazione orientata agli oggetti del percorso C di Coddy. Lezione 38 di 61.
Finora abbiamo usato puntatori a funzione come variabili autonome o li abbiamo passati come argomenti. Il passo successivo verso il polimorfismo consiste nell’inserire un puntatore a funzione direttamente all’interno di una struct, dando alla struct un comportamento proprio.
Quando una struct contiene un puntatore a funzione, ogni istanza può contenere una funzione diversa. Questo significa che due oggetti dello stesso tipo possono comportarsi in modo diverso quando chiami il loro puntatore a funzione:
typedef void (*PrintFunc)(const char*);
typedef struct {
const char* name;
PrintFunc print; // Puntatore a funzione come membro
} Printer;La struct Printer ora ha due membri: dati (name) e comportamento (print). Per usarla, assegni una funzione al puntatore durante l'inizializzazione:
void loud_print(const char* msg) {
printf("!!! %s !!!\n", msg);
}
int main() {
Printer p;
p.name = "Alert";
p.print = loud_print;
p.print("Hello"); // Output: !!! Hello !!!
return 0;
}Nota come chiamiamo la funzione tramite la struct: p.print("Hello"). Questo assomiglia molto alla chiamata di un metodo su un oggetto in altri linguaggi. La struct contiene sia i propri dati sia la funzione che opera su di essa.
Questo schema è alla base del polimorfismo in C: a istanze diverse possono essere assegnate funzioni diverse, producendo comportamenti diversi a partire dallo stesso tipo di struct.
Sfida
FacileCostruiamo un sistema Notifier che dimostra come le struct possano contenere il proprio comportamento tramite puntatori a funzione.
Creerai due file per organizzare il codice:
notifier.h: definisci un tipo puntatore a funzione chiamatoNotifyFuncche accetta un parametroconst char*e non restituisce nulla. Poi definisci una structNotifierche contiene unname(unconst char*) e un puntatore a funzionenotifydi tipoNotifyFunc.main.c: includi il tuo header e implementa due funzioni di notifica:alert_notify: stampa il messaggio nel formato:[ALERT] messageinfo_notify: stampa il messaggio nel formato:[INFO] message
Notifier, assegna la funzione appropriata in base all'input e richiama la notifica tramite il puntatore a funzione della struct.
Il programma riceverà due input: un tipo di notifica (1 per alert, 2 per info) e un messaggio da visualizzare.
In base al tipo, assegna la funzione corrispondente al membro notify del notifier, quindi richiamala tramite la struct per visualizzare il messaggio.
Esempio di output quando il tipo è 1 e il messaggio è "System starting":
[ALERT] System startingEsempio di output quando il tipo è 2 e il messaggio è "All systems normal":
[INFO] All systems normalRicorda di usare include guard nel file header e di richiamare la funzione tramite il membro della struct: n.notify(message)
Provalo tu
#include <stdio.h>
#include "notifier.h"
// TODO: Implementa la funzione alert_notify
// Deve stampare: [ALERT] message
// TODO: Implementa la funzione info_notify
// Deve stampare: [INFO] message
int main() {
int type;
char message[256];
// Leggi l'input
scanf("%d", &type);
getchar(); // consuma il carattere di nuova riga
fgets(message, sizeof(message), stdin);
// Rimuovi il carattere di nuova riga finale da message, se presente
int len = 0;
while (message[len] != '\0') len++;
if (len > 0 && message[len-1] == '\n') message[len-1] = '\0';
// TODO: Crea un'istanza di Notifier
// TODO: In base a type (1 per alert, 2 per info),
// assegna la funzione appropriata al membro notify di notifier
// TODO: Richiama la notifica tramite il puntatore a funzione della struct
// Usa: n.notify(message)
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