Il concetto di interfaccia
Fa parte della sezione Programmazione orientata agli oggetti del percorso C di Coddy. Lezione 40 di 61.
Finora, le nostre struct hanno mescolato dati e comportamento: per esempio, un nome insieme a un puntatore a funzione. Ma cosa succederebbe se una struct contenesse solo puntatori a funzione? Questo crea qualcosa di potente: un’interfaccia.
Un'interfaccia definisce quali operazioni sono disponibili senza specificare how funzionano. È un contratto che dice «qualsiasi oggetto che implementa questa interfaccia deve fornire queste funzioni».
typedef void (*LogFunc)(const char* message);
typedef struct {
LogFunc log;
} ILogger;La struct ILogger non contiene altro che un puntatore a funzione. Non ha dati propri. Descrive esclusivamente un comportamento. Il prefisso "I" è una convenzione comune che indica che si tratta di un'interfaccia.
Al codice che accetta un ILogger non importa dove venga inviato il messaggio di log. Potrebbe stamparlo sulla console, scriverlo in un file o inviare dati tramite una rete. Il chiamante sa solo di poter chiamare log:
void process(ILogger* logger, const char* msg) {
logger->log(msg); // Non sappiamo COME registra i messaggi
}Questa separazione è l’essenza del polimorfismo. La funzione process funziona con qualsiasi implementazione di logger. Puoi sostituire i comportamenti senza modificare il codice della funzione. Nella prossima lezione, creerai implementazioni concrete che soddisfano questo contratto dell’interfaccia.
Sfida
FacileCreiamo un'interfaccia ICalculator: una struct che contiene solo puntatori a funzione e definisce quali operazioni deve supportare qualsiasi calcolatrice, senza specificare come funzionano.
Creerai due file per organizzare il codice:
calculator.h: definisci qui la tua interfaccia. Crea un tipo di puntatore a funzione chiamatoBinaryOpche accetta due parametriinte restituisce unint. Poi definisci una structICalculatorche contiene solo due puntatori a funzione:operate(di tipoBinaryOp) edescribe(un puntatore a funzione che non accetta parametri e non restituisce nulla). Questa struct è puramente un'interfaccia. Non contiene dati, solo comportamenti.main.c: includi il tuo header e implementa funzioni concrete che soddisfino l'interfaccia:add: restituisce la somma di due numeri interimultiply: restituisce il prodotto di due numeri interidescribe_add: stampaAdditiondescribe_multiply: stampaMultiplication
ICalculator, collegala in base all'input e usala per eseguire un calcolo.
Il programma riceverà tre input: due numeri interi e un codice operazione (1 per l'addizione, 2 per la moltiplicazione).
In base al codice operazione, collega la tua ICalculator alla coppia di funzioni appropriata. Poi chiama describe tramite l'interfaccia per stampare il nome dell'operazione, quindi chiama operate per calcolare e stampare il risultato.
Esempio di output quando gli input sono 5, 3 e 1:
Addition
8Esempio di output quando gli input sono 4, 7 e 2:
Multiplication
28L'idea chiave è che la tua struct ICalculator definisce un contratto: qualsiasi codice la utilizzi sa di poter chiamare describe e operate, senza sapere quali funzioni specifiche siano collegate. Ricordati di usare le include guard nel tuo file header.
Provalo tu
#include <stdio.h>
#include "calculator.h"
// TODO: Implementa la funzione add
// Restituisce la somma di due numeri interi
// TODO: Implementa la funzione multiply
// Restituisce il prodotto di due numeri interi
// TODO: Implementa la funzione describe_add
// Stampa "Addition"
// TODO: Implementa la funzione describe_multiply
// Stampa "Multiplication"
int main() {
int num1, num2, op_code;
scanf("%d", &num1);
scanf("%d", &num2);
scanf("%d", &op_code);
// TODO: Crea un'istanza di ICalculator
// TODO: In base a op_code (1 per add, 2 per multiply),
// collega la calcolatrice alle funzioni appropriate
// TODO: Chiama describe tramite l'interfaccia
// TODO: chiama operate tramite l'interfaccia e stampa il risultato
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