Pointeurs de fonctions dans les structures
Fait partie de la section Object Oriented Programming du Journey C de Coddy — leçon 38 sur 61.
Jusqu'à présent, nous avons utilisé des pointeurs de fonction comme variables autonomes ou nous les avons passés comme arguments. La prochaine étape vers le polymorphisme consiste à intégrer un pointeur de fonction directement à l'intérieur d'une struct — donnant à la struct son propre comportement.
Lorsqu'une structure contient un pointeur de fonction, chaque instance peut contenir une fonction différente. Cela signifie que deux objets du même type peuvent se comporter différemment lorsque vous appelez leur pointeur de fonction :
typedef void (*PrintFunc)(const char*);
typedef struct {
const char* name;
PrintFunc print; // Pointeur de fonction en tant que membre
} Printer;La structure Printer possède désormais deux membres : des données (name) et un comportement (print). Pour l'utiliser, vous assignez une fonction au pointeur lors de l'initialisation :
void loud_print(const char* msg) {
printf("!!! %s !!!\n", msg);
}
int main() {
Printer p;
p.name = "Alert";
p.print = loud_print;
p.print("Hello"); // Sortie : !!! Hello !!!
return 0;
}Remarquez comment nous appelons la fonction via la structure : p.print("Hello"). Cela ressemble étrangement à l'appel d'une méthode sur un objet dans d'autres langages. La structure transporte à la fois ses données et la fonction qui opère sur celles-ci.
Ce modèle est le fondement du polymorphisme en C — différentes instances peuvent avoir différentes fonctions assignées, produisant des comportements différents à partir du même type struct.
Défi
FacileConstruisons un système Notifier qui démontre comment les structures peuvent porter leur propre comportement via des pointeurs de fonction.
Vous allez créer deux fichiers pour organiser votre code :
notifier.h: Définissez un type de pointeur de fonction appeléNotifyFuncqui prend un paramètreconst char*et ne renvoie rien. Définissez ensuite une structureNotifierqui contient unname(unconst char*) et un pointeur de fonctionnotifyde typeNotifyFunc.main.c: Incluez votre en-tête et implémentez deux fonctions de notification :alert_notify— affiche le message au format :[ALERT] messageinfo_notify— affiche le message au format :[INFO] message
Notifier, liez la fonction appropriée en fonction de l'entrée, et appelez la notification via le pointeur de fonction de la structure.
Votre programme recevra deux entrées : un type de notification (1 pour alert, 2 pour info) et un message à afficher.
Selon le type, assignez la fonction correspondante au membre notify de votre notifier, puis appelez-la via la structure pour afficher le message.
Exemple de sortie lorsque le type est 1 et le message est "System starting" :
[ALERT] System startingExemple de sortie lorsque le type est 2 et le message est "All systems normal" :
[INFO] All systems normalN'oubliez pas d'utiliser des gardes d'inclusion dans votre fichier d'en-tête, et d'appeler la fonction via le membre de la structure : n.notify(message)
Aide-mémoire
Les pointeurs de fonction peuvent être intégrés directement dans des structures, donnant à chaque instance son propre comportement. C'est une base pour le polymorphisme en C.
Définir une structure avec un pointeur de fonction
Tout d'abord, définissez un type de pointeur de fonction, puis incluez-le en tant que membre de la structure :
typedef void (*PrintFunc)(const char*);
typedef struct {
const char* name;
PrintFunc print; // Function pointer as a member
} Printer;Utiliser la structure
Affectez une fonction au pointeur lors de l'initialisation, puis appelez-la via la structure :
void loud_print(const char* msg) {
printf("!!! %s !!!\n", msg);
}
int main() {
Printer p;
p.name = "Alert";
p.print = loud_print;
p.print("Hello"); // Output: !!! Hello !!!
return 0;
}La syntaxe p.print("Hello") appelle la fonction via la structure, de manière similaire à l'appel d'une méthode sur un objet dans d'autres langages.
Comportement polymorphe
Différentes instances du même type de structure peuvent avoir des fonctions différentes assignées, produisant des comportements différents à partir du même type de structure.
Essayez vous-même
#include <stdio.h>
#include "notifier.h"
// TODO : Implémenter la fonction alert_notify
// Devrait afficher : [ALERT] message
// TODO : Implémenter la fonction info_notify
// Devrait afficher : [INFO] message
int main() {
int type;
char message[256];
// Lire l'entrée
scanf("%d", &type);
getchar(); // consommer le saut de ligne
fgets(message, sizeof(message), stdin);
// Supprimer le saut de ligne à la fin du message s'il est présent
int len = 0;
while (message[len] != '\0') len++;
if (len > 0 && message[len-1] == '\n') message[len-1] = '\0';
// TODO : Créer une instance de Notifier
// TODO : Selon le type (1 pour alert, 2 pour info),
// assigner la fonction appropriée au membre notify du notifier
// TODO : Appeler la notification via le pointeur de fonction de la structure
// Utiliser : n.notify(message)
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 Object Oriented Programming
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 cercle