Wrapper générique
Fait partie de la section Programmation Orientée Objet du Journey C de Coddy. Leçon 50 sur 61.
Un void* seul peut stocker n’importe quelle donnée, mais il présente un défaut critique : vous perdez la trace du type qu’il contient. Pour construire des conteneurs génériques réellement utiles, nous devons associer le pointeur de données aux informations de type. C’est là qu’intervient le modèle du wrapper générique.
L’idée est simple : créer une structure qui regroupe un void* avec une énumération qui identifie le type stocké. Ainsi, le wrapper sait toujours comment interpréter son contenu.
typedef enum {
TYPE_INT,
TYPE_STRING
} DataType;
typedef struct {
void* data;
DataType type;
} Wrapper;Lors du stockage de données, vous allouez de la mémoire pour la valeur réelle et enregistrez son type. Lors de la récupération, vous vérifiez le type avant d’effectuer la conversion :
Wrapper wrap_int(int value) {
int* p = malloc(sizeof(int));
*p = value;
return (Wrapper){ .data = p, .type = TYPE_INT };
}
void print_wrapper(Wrapper* w) {
if (w->type == TYPE_INT) {
printf("%d\n", *(int*)w->data);
} else if (w->type == TYPE_STRING) {
printf("%s\n", (char*)w->data);
}
}Ce modèle constitue la base pour créer des conteneurs génériques à typage sûr en C. L’énumération agit comme une balise de type à l’exécution, permettant à votre code de prendre des décisions sûres sur la manière de traiter les données stockées.
Défi
FacileConstruisons un système générique de wrappers sûr du point de vue des types, capable de stocker soit un entier, soit une chaîne de caractères, tout en gardant trace du type qu’il contient afin de pouvoir récupérer et afficher les données en toute sécurité par la suite.
Vous organiserez votre code dans trois fichiers :
wrapper.h: définissez une énumérationDataTypeavec les valeursTYPE_INTetTYPE_STRING. Définissez ensuite une structureWrapperqui regroupe un pointeur de donnéesvoid*et un champDataType. Déclarez les prototypes des fonctions permettant de créer les wrappers et d’afficher leur contenu.wrapper.c: implémentez les fonctionnalités du wrapper :wrap_int: prend un entier, lui alloue de la mémoire, stocke la valeur et renvoie un Wrapper avec l’étiquette de type appropriéewrap_string: prend une chaîne de caractères (char*), alloue de la mémoire, copie la chaîne et renvoie un Wrapper avec l’étiquette de type chaîneprint_wrapper: vérifie l’étiquette de type et affiche les données de manière appropriée (l’entier tel quel, la chaîne telle quelle)free_wrapper: libère les données allouées dynamiquement à l’intérieur du wrapper
main.c: assemblez le tout. Lisez un indicateur de type (ipour un entier,spour une chaîne), suivi de la valeur. Créez le wrapper approprié, affichez son contenu et libérez la mémoire.
Votre programme recevra deux entrées :
- Un indicateur de type :
ipour un entier ouspour une chaîne - La valeur à encapsuler
Exemple de sortie lorsque les entrées sont i et 42 :
42Exemple de sortie lorsque les entrées sont s et Hello :
HelloExemple de sortie lorsque les entrées sont i et -100 :
-100Exemple de sortie lorsque les entrées sont s et Generic Programming :
Generic ProgrammingN’oubliez pas d’utiliser des gardes d’inclusion dans votre fichier d’en-tête. Pour copier une chaîne, allouez suffisamment d’espace pour la chaîne et le terminateur nul à l’aide de strlen et strcpy.
Essayez vous-même
#include <stdio.h>
#include <string.h>
#include "wrapper.h"
int main() {
char type;
scanf("%c", &type);
getchar(); // consommer le saut de ligne
Wrapper w;
if (type == 'i') {
int value;
scanf("%d", &value);
// TODO: Créer un wrapper d'entier en utilisant wrap_int
} else if (type == 's') {
char str[256];
fgets(str, sizeof(str), stdin);
// Supprimer le saut de ligne final s'il est présent
str[strcspn(str, "\n")] = '\0';
// TODO: Créer un wrapper de chaîne en utilisant wrap_string
}
// TODO: Afficher le contenu du wrapper en utilisant print_wrapper
// TODO: Libérer la mémoire du wrapper en utilisant free_wrapper
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ète7Pointeurs sur fonctions
Déclaration de pointeurs sur fonctionsAppel de pointeurs sur fonctionsTypedef pour les pointeurs sur fonctionsPassage de fonctions en argumentsRécapitulatif : Dispatcher de calculatrice10Conteneurs génériques
Rappel sur les pointeurs voidWrapper génériqueÉchange génériqueComparaison génériqueRappel : tableaux génériques2Objets 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