Menu
Coddy logo textTech

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.

challenge icon

Défi

Facile

Construisons 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é NotifyFunc qui prend un paramètre const char* et ne renvoie rien. Définissez ensuite une structure Notifier qui contient un name (un const char*) et un pointeur de fonction notify de type NotifyFunc.
  • main.c : Incluez votre en-tête et implémentez deux fonctions de notification :
    • alert_notify — affiche le message au format : [ALERT] message
    • info_notify — affiche le message au format : [INFO] message
    Ensuite, créez une instance de 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 starting

Exemple de sortie lorsque le type est 2 et le message est "All systems normal" :

[INFO] All systems normal

N'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;
}
quiz iconTestez-vous

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