1. Introduzione
Il linguaggio C è amato da molti programmatori per il suo background storico e il controllo a basso livello. Tuttavia, C non è un linguaggio orientato agli oggetti. In altre parole, a differenza di Java o C++, C stesso non supporta nativamente le funzionalità orientate agli oggetti come classi, ereditarietà o incapsulamento. Detto ciò, è possibile imitare i concetti della programmazione orientata agli oggetti (OOP) in C e ottenere un certo livello di funzionalità OOP. In questo articolo spiegheremo come implementare la programmazione orientata agli oggetti in C, concentrandoci sui concetti chiave di incapsulamento, ereditarietà e polimorfismo.
2. Concetti di base della programmazione orientata agli oggetti
La programmazione orientata agli oggetti (OOP) mira a gestire i dati e i metodi che operano su quei dati come un’unica unità. Questo approccio aiuta a chiarire la struttura del programma e migliora riusabilità e la manutenibilità. I concetti principali dell’OOP sono incapsulamento, ereditarietà e polimorfismo. Sebbene C non supporti direttamente queste funzionalità, con un po’ di ingegnosità è possibile implementarle in modo simile.
2.1 Incapsulamento
L’incapsulamento significa raggruppare dati e le loro operazioni (metodi) in un’unica unità e controllare l’accesso dall’esterno. In C, è possibile raggruppare i dati usando le struct. Le struct svolgono un ruolo simile alle classi in quanto combinano più elementi di dati in una singola struttura.
typedef struct {
int age;
char name[50];
} Person;
In questa struct, il tipo di dato Person incapsula sia le informazioni sull’età sia sul nome. Questo ti permette di creare e operare su istanze di Person.
2.2 Ereditarietà
C non dispone di una funzionalità nativa di ereditarietà, quindi non è possibile creare relazioni padre‑figlio come con le classi. Tuttavia, includendo una struct come membro di un’altra, è possibile ottenere un meccanismo simile all’ereditarietà.
typedef struct {
int age;
} Parent;
typedef struct {
Parent parent;
int studentID;
} Child;
In questo codice, la struct Child contiene una struct Parent, rappresentando una forma di pseudo‑ereditarietà.
2.3 Polimorfismo
Il polimorfismo indica la capacità della stessa operazione di comportarsi in modo diverso a seconda del tipo di oggetto. In C, è possibile ottenerlo usando i puntatori a funzione. Un puntatore a funzione è una variabile che contiene l’indirizzo di una funzione, consentendo di chiamare dinamicamente funzioni diverse.
typedef int (*OperationFunc)(int, int);
int add(int a, int b) {
return a + b;
}
int multiply(int a, int b) {
return a * b;
}
OperationFunc op = add; // Set to add function
printf("%d", op(3, 4)); // Output: 7
op = multiply; // Switch to multiply function
printf("%d", op(3, 4)); // Output: 12
Come mostrato, è possibile eseguire operazioni diverse usando lo stesso puntatore a funzione.

3. Come implementare le classi in C
Per portare la programmazione orientata agli oggetti in C, è necessario simulare il concetto di classi. Questo si ottiene combinando struct e puntatori a funzione per creare strutture simili a classi.
3.1 Usare le struct come classi
Per implementare le classi in C, utilizza le struct per raggruppare dati e metodi insieme. I metodi sono definiti come funzioni e gestiti all’interno della struct tramite puntatori a funzione.
typedef struct {
int age;
void (*setAge)(struct Person*, int);
int (*getAge)(struct Person*);
} Person;
void setAge(struct Person* p, int age) {
p->age = age;
}
int getAge(struct Person* p) {
return p->age;
}
Person person = {0, setAge, getAge};
person.setAge(&person, 25);
printf("Age: %d", person.getAge(&person)); // Output: 25
In questo esempio, la struct Person ha i metodi setAge e getAge, consentendo un comportamento simile a quello di una classe.
4. Implementazione dei metodi
Per riprodurre i “metodi”, una caratteristica chiave dell’OOP, in C, utilizza i puntatori a funzione. Questo ti permette di definire i metodi come membri della struct.
typedef struct {
int age;
void (*setAge)(struct Person*, int);
} Person;
void setAge(struct Person* p, int age) {
p->age = age;
}
5. Riepilogo e Applicazioni
Anche se è possibile implementare funzionalità orientate agli oggetti in C, tieni presente che il linguaggio stesso non supporta nativamente l’OOP. Avrai bisogno di un po’ di creatività, facendo pieno uso di struct, puntatori a funzioni e gestione della memoria per incorporare concetti simili a classi e ereditarietà.



