Définir des structures opaques
Fait partie de la section Programmation Orientée Objet du Journey C de Coddy. Leçon 18 sur 61.
Maintenant que tu comprends le concept des pointeurs opaques, voyons comment compléter le pattern. L’en-tête déclare qu’un type existe, mais le fichier source est l’endroit où tu définis ce qu’il contient réellement.
Voici la configuration complète. D'abord, l'en-tête contenant uniquement la déclaration anticipée :
// counter.h
#ifndef COUNTER_H
#define COUNTER_H
typedef struct Counter Counter; // Type incomplet
Counter *create_counter(int start);
void free_counter(Counter *c);
#endif
Ensuite, le fichier source contient la définition réelle de la structure :
// counter.c
#include "counter.h"
#include <stdlib.h>
struct Counter {
int value; // Caché de l'extérieur !
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);
}
Le point essentiel : struct Counter { ... } apparaît uniquement dans le fichier .c. Tout fichier qui inclut counter.h sait que Counter existe, mais ne peut pas voir value ou step. Tenter d’écrire c->value dans main.c provoquerait une erreur du compilateur : les membres sont véritablement invisibles.
Cette séparation constitue le fondement de l’encapsulation en C. L’étape suivante consiste à fournir un accès contrôlé par l’intermédiaire de fonctions getter et setter.
Défi
FacileConstruisons un module Timer qui démontre le modèle du pointeur opaque. Tu vas t’entraîner à dissimuler la définition de la structure dans le fichier source, rendant ses membres internes complètement invisibles pour tout code qui utilise ton module.
Tu vas créer trois fichiers :
timer.h: c’est ton interface publique. Déclare un type opaqueTimeren utilisant uniquement une déclaration anticipée : aucune définition de structure ici ! Déclare également deux fonctions :create_timer(qui prend un entier représentant un nombre de secondes et renvoie un pointeur vers un Timer) etfree_timer(qui prend un pointeur vers un Timer et effectue le nettoyage). Utilise des gardes d’inclusion avec le symboleTIMER_H.timer.c: c’est ici que se trouve le secret. Définis la véritablestruct Timeravec deux membres cachés :int secondsetint running(utilise 1 pour « en cours d’exécution » et 0 pour « arrêté »). Implémente ton constructeur pour allouer la structure, initialisersecondsavec la valeur fournie et définirrunningsur 1. Implémente le destructeur pour libérer la mémoire.main.c: utilise ton module Timer pour créer un minuteur et confirmer qu’il a été créé avec succès. Comme les membres de la structure sont cachés, tu ne peux pas y accéder directement. C’est tout l’intérêt ! Affiche simplement un message confirmant la création, puis libère le minuteur et affiche un message de nettoyage.
Tu recevras une entrée : le nombre de secondes (un entier) avec lequel initialiser le minuteur.
Dans ton fichier principal, crée un minuteur avec la valeur de secondes fournie. Affiche un message de création, puis libère le minuteur et affiche une confirmation.
Affiche la sortie dans ce format :
Timer created
Timer freedL’idée essentielle ici est que main.c peut travailler avec des pointeurs vers des Timers, mais n’a aucun moyen d’accéder directement à seconds ou à running. Tenter d’écrire t->seconds dans main.c provoquerait une erreur du compilateur, car le corps de la structure n’est défini que dans timer.c. C’est cela, le véritable encapsulage : les détails d’implémentation sont complètement cachés aux utilisateurs de ton module.
Essayez vous-même
#include <stdio.h>
#include "timer.h"
int main() {
int seconds;
scanf("%d", &seconds);
// TODO: Créer un timer avec la valeur de secondes fournie
// TODO: Print "Timer created"
// TODO: Libérer le timer
// TODO: Afficher "Timer freed"
return 0;
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation Orientée Objet
1Bases de la programmation modulaire
Fichiers d'en-têteGardes d'inclusionFichiers sourcesFonctions statiquesRécapitulatif : Calculatrice modulaire4Encapsulation
Concept des pointeurs opaquesDéfinir des structures opaquesGetters et settersValidation dans les settersRécapitulatif : La boîte secrète2Objets et méthodes
Structs comme objetsLe pointeur 'Self'Rigueur du mot-clé constPointeur vs ValeurMéthodes utilitairesRécapitulatif : Point Manager5Projet : Compte bancaire simple
Configuration du projetImplémentation du compte8Polymorphisme
Pointeurs de fonctions dans les structuresSimulation de méthodesLe concept d'interfaceImplémentation d'interfacesItération polymorphiqueRécapitulatif : Greeter11Patrons de conception en C
Patron SingletonPatron FabriquePatron ItérateurRécapitulatif : Logger Factory3Cycle de vie des objets
Pattern de constructeurPattern de destructeurInitialisation sur la pileCopie profondeRécapitulatif : String Wrapper6Héritage par composition
Imbrication de structLa règle du premier membreAccès aux membres parentsUpcastingRécapitulatif : Hiérarchie des formes9Projet : Dessinateur de formes
Aperçu du projetImplémentation du cercleImplémentation du rectangleUtilisation polymorpheConteneur de formesEntraînez-vous par vous-même : Compilateur C en ligne