Le concept d'interface
Fait partie de la section Object Oriented Programming du Journey C de Coddy — leçon 40 sur 61.
Jusqu'à présent, nos structures ont mélangé les données et le comportement — un nom aux côtés d'un pointeur de fonction, par exemple. Mais que se passerait-il si une structure ne contenait que des pointeurs de fonction ? Cela crée quelque chose de puissant : une interface.
Une interface définit quelles opérations sont disponibles sans spécifier comment elles fonctionnent. C'est un contrat qui stipule que « tout objet implémentant cette interface doit fournir ces fonctions ».
typedef void (*LogFunc)(const char* message);
typedef struct {
LogFunc log;
} ILogger;La structure ILogger ne contient rien d'autre qu'un pointeur de fonction. Elle ne possède aucune donnée propre — elle décrit purement un comportement. Le préfixe « I » est une convention courante indiquant qu'il s'agit d'une interface.
Tout code qui accepte un ILogger ne se soucie pas de l'endroit où le message de journalisation est envoyé. Il peut s'agir d'une impression sur la console, d'une écriture dans un fichier ou de l'envoi de données sur un réseau. L'appelant sait simplement qu'il peut appeler log :
void process(ILogger* logger, const char* msg) {
logger->log(msg); // Nous ne savons pas COMMENT il enregistre les logs
}Cette séparation est l'essence même du polymorphisme. La fonction process fonctionne avec n'importe quelle implémentation de logger — vous pouvez échanger les comportements sans modifier le code de la fonction. Dans la prochaine leçon, vous créerez des implémentations concrètes qui respectent ce contrat d'interface.
Défi
FacileConstruisons une interface ICalculator — une structure qui ne contient que des pointeurs de fonction, définissant les opérations que tout calculateur doit prendre en charge sans spécifier comment elles fonctionnent.
Vous allez créer deux fichiers pour organiser votre code :
calculator.h: Définissez votre interface ici. Créez un type de pointeur de fonction appeléBinaryOpqui prend deux paramètresintet retourne unint. Définissez ensuite une structureICalculatorqui ne contient que deux pointeurs de fonction :operate(de typeBinaryOp) etdescribe(un pointeur de fonction qui ne prend aucun paramètre et ne retourne rien). Cette structure est purement une interface — elle ne contient aucune donnée, seulement du comportement.main.c: Incluez votre en-tête et implémentez des fonctions concrètes qui peuvent remplir l'interface :add— retourne la somme de deux entiersmultiply— retourne le produit de deux entiersdescribe_add— afficheAdditiondescribe_multiply— afficheMultiplication
ICalculator, connectez-la en fonction de l'entrée, et utilisez-la pour effectuer un calcul.
Votre programme recevra trois entrées : deux entiers et un code d'opération (1 pour l'addition, 2 pour la multiplication).
En fonction du code d'opération, connectez votre ICalculator avec la paire de fonctions appropriée. Appelez ensuite describe via l'interface pour afficher le nom de l'opération, suivi de l'appel à operate pour calculer et afficher le résultat.
Exemple de sortie lorsque les entrées sont 5, 3, et 1 :
Addition
8Exemple de sortie lorsque les entrées sont 4, 7, et 2 :
Multiplication
28L'idée clé est que votre structure ICalculator définit un contrat — tout code l'utilisant sait qu'il peut appeler describe et operate, sans savoir quelles fonctions spécifiques sont connectées. N'oubliez pas d'utiliser des gardes d'inclusion dans votre fichier d'en-tête.
Aide-mémoire
Une interface est une structure qui ne contient que des pointeurs de fonction, définissant quelles opérations sont disponibles sans spécifier comment elles fonctionnent.
Définir une interface :
typedef void (*LogFunc)(const char* message);
typedef struct {
LogFunc log;
} ILogger;Le préfixe « I » est une convention courante indiquant qu'il s'agit d'une interface. La structure ne contient aucune donnée — elle décrit purement un comportement.
Utiliser une interface :
void process(ILogger* logger, const char* msg) {
logger->log(msg); // Nous ne savons pas COMMENT il enregistre les logs
}Cette séparation permet le polymorphisme — la fonction fonctionne avec n'importe quelle implémentation de l'interface, vous permettant de changer les comportements sans modifier le code de la fonction.
Essayez vous-même
#include <stdio.h>
#include "calculator.h"
// TODO: Implémenter la fonction add
// Retourne la somme de deux entiers
// TODO: Implémenter la fonction multiply
// Retourne le produit de deux entiers
// TODO: Implémenter la fonction describe_add
// Affiche "Addition"
// TODO: Implémenter la fonction describe_multiply
// Affiche "Multiplication"
int main() {
int num1, num2, op_code;
scanf("%d", &num1);
scanf("%d", &num2);
scanf("%d", &op_code);
// TODO: Créer une instance de ICalculator
// TODO: En fonction de op_code (1 pour add, 2 pour multiply),
// lier le calculateur avec les fonctions appropriées
// TODO: Appeler describe via l'interface
// TODO: Appeler operate via l'interface et afficher le résultat
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