Menu
Coddy logo textTech

Definire struct opache

Fa parte della sezione Programmazione orientata agli oggetti del percorso C di Coddy. Lezione 18 di 61.

Ora che hai compreso il concetto di puntatori opachi, vediamo come completare lo schema. L'intestazione dichiara che esiste un tipo, ma è nel file sorgente che definisci cosa contiene effettivamente.

Ecco la configurazione completa. Per prima cosa, l'header con solo la dichiarazione anticipata:

// counter.h
#ifndef COUNTER_H
#define COUNTER_H

typedef struct Counter Counter;  // Tipo incompleto

Counter *create_counter(int start);
void free_counter(Counter *c);

#endif

Quindi, il file sorgente contiene la definizione effettiva della struct:

// counter.c
#include "counter.h"
#include <stdlib.h>

struct Counter {
    int value;      // Nascosto all'esterno!
    int step;
};

Counter *create_counter(int start) {
    Counter *c = malloc(sizeof(Counter));
    c->value = start;
    c->step = 1;
    return c;
}

void free_counter(Counter *c) {
    free(c);
}

Il punto chiave: struct Counter { ... } compare solo nel file .c. Qualsiasi file che include counter.h sa che Counter esiste, ma non può vedere value o step. Tentare di scrivere c->value in main.c causerebbe un errore del compilatore: i membri sono davvero invisibili.

Questa separazione è alla base dell'incapsulamento in C. Il passo successivo consiste nel fornire un accesso controllato tramite funzioni getter e setter.

challenge icon

Sfida

Facile

Costruiamo un modulo Timer che dimostra il pattern del puntatore opaco. Ti eserciterai a nascondere la definizione della struttura nel file sorgente, rendendo i suoi membri interni completamente invisibili al codice che usa il tuo modulo.

Creerai tre file:

  • timer.h: questa è la tua interfaccia pubblica. Dichiara un tipo opaco Timer usando solo una dichiarazione anticipata: qui non inserire il corpo della struttura! Dichiara anche due funzioni: create_timer (accetta un intero che rappresenta i secondi e restituisce un puntatore a Timer) e free_timer (accetta un puntatore a Timer ed esegue la pulizia). Usa le include guard con il simbolo TIMER_H.
  • timer.c: qui si trova il segreto. Definisci la vera struct Timer con due membri nascosti: int seconds e int running (usa 1 per lo stato in esecuzione, 0 per lo stato fermo). Implementa il costruttore per allocare la struttura, inizializzare seconds con il valore fornito e impostare running a 1. Implementa il distruttore per liberare la memoria.
  • main.c: usa il tuo modulo Timer per creare un timer e confermare che sia stato creato correttamente. Poiché i membri della struttura sono nascosti, non puoi accedervi direttamente. È proprio questo il punto! Stampa semplicemente un messaggio di conferma della creazione, poi libera il timer e stampa un messaggio di pulizia.

Riceverai un input: il numero di secondi (un intero) con cui inizializzare il timer.

Nel tuo file principale, crea un timer con il valore dei secondi fornito. Stampa un messaggio di creazione, poi libera il timer e stampa una conferma.

Stampa l'output in questo formato:

Timer created
Timer freed

L'intuizione fondamentale è che main.c può lavorare con puntatori a Timer, ma non ha modo di accedere direttamente a seconds o running. Tentare di scrivere t->seconds in main.c causerebbe un errore del compilatore, perché il corpo della struttura è definito solo in timer.c. Questa è vera incapsulazione: i dettagli di implementazione sono completamente nascosti agli utenti del tuo modulo.

Provalo tu

#include <stdio.h>
#include "timer.h"

int main() {
    int seconds;
    scanf("%d", &seconds);
    
    // TODO: Crea un timer con il valore di seconds fornito
    
    // TODO: Stampa "Timer created"
    
    // TODO: Libera la memoria del timer
    
    // TODO: Stampa "Timer freed"
    
    return 0;
}
quiz iconMettiti alla prova

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

Esercitati da solo: Compilatore C online