Interfaces en C++ : Guide pour ceux qui en ont assez de chercher sur Google
\n\nSi vous avez déjà programmé en Java ou en C#, puis êtes passé au C++, vous vous êtes sûrement demandé : "Où est le mot-clé interface ?". Spoiler : il n'existe pas. En C++, les interfaces sont implémentées différemment — via des classes abstraites. Et ce n'est pas un bug, mais une fonctionnalité qui offre une flexibilité incroyable.
\n\nSur Stack Overflow, la question "How do you declare an interface in C++?" recueille des milliers de vues. Cela signifie que même les développeurs expérimentés s'y perdent parfois. Aujourd'hui, nous allons une fois pour toutes comprendre comment déclarer une interface en C++, pour que votre code soit propre et votre compilateur satisfait.
\n\nQu'est-ce qu'une interface en C++ ? (Spoiler : c'est une classe abstraite)
\n\nEn POO classique, une interface est un contrat. La classe qui implémente l'interface doit fournir une implémentation de toutes ses méthodes. En C++, ce rôle est joué par une classe abstraite — une classe contenant au moins une fonction virtuelle pure (pure virtual function).
\n\nRetenez la règle principale :
\n- \n
- Interface = classe où toutes les méthodes sont virtuelles pures. \n
- Classe abstraite = classe où au moins une méthode est virtuelle pure (mais elle peut aussi avoir des méthodes normales avec implémentation). \n
Pour une interface pure, nous utilisons la première option : aucune logique, uniquement des déclarations.
\n\nComment déclarer une interface pure : syntaxe de base
\n\nVoici un exemple minimal d'interface pour une figure géométrique :
\n\nclass IShape {\npublic:\n virtual double area() const = 0; // Fonction virtuelle pure\n virtual double perimeter() const = 0; // Une autre\n virtual ~IShape() {} // Destructeur virtuel — obligatoire !\n};\n\nNotez le = 0 à la fin de la déclaration. C'est le marqueur magique "virtuel pur". Une telle méthode n'a pas de corps (d'implémentation) dans la classe de base.
Points clés :
\n- \n
- Préfixe I dans le nom de la classe — une convention non écrite pour les interfaces (I = Interface). Vous pouvez ne pas l'utiliser, mais cela facilite la lecture du code. \n
- Destructeur virtuel obligatoire. Si vous supprimez un objet via un pointeur vers l'interface, sans destructeur virtuel, le comportement est indéfini (autrement dit, le programme plantera). \n
- Toutes les méthodes sont public — l'interface doit être accessible depuis l'extérieur. \n
Implémentation de l'interface : des paroles aux actes
\n\nÉcrivons maintenant une classe qui implémente notre interface IShape. Que ce soit un cercle :
class Circle : public IShape {\nprivate:\n double radius;\npublic:\n explicit Circle(double r) : radius(r) {}\n\n double area() const override {\n return 3.14159 * radius * radius;\n }\n\n double perimeter() const override {\n return 2 * 3.14159 * radius;\n }\n};\n\nLe mot-clé override (C++11 et versions ultérieures) n'est pas obligatoire, mais fortement recommandé. Il force le compilateur à vérifier que vous redéfinissez bien une méthode virtuelle de la classe de base. Vous avez fait une faute de frappe dans le nom ? Le compilateur dira : "Erreur ! Cette méthode n'existe pas dans l'interface".
Polymorphisme en action
\n\nMaintenant, la partie intéressante — nous pouvons travailler avec différentes figures via une interface unique :
\n\nvoid printShapeInfo(const IShape& shape) {\n std::cout << "Area: " << shape.area() << "\\n";\n std::cout << "Perimeter: " << shape.perimeter() << "\\n";\n}\n\nint main() {\n Circle c(5.0);\n printShapeInfo(c); // Ça marche !\n return 0;\n}\n\nLa fonction printShapeInfo prend une référence à IShape. Peu importe quel objet est passé — un cercle, un carré ou un triangle. Tant qu'ils implémentent l'interface, tout fonctionnera. C'est cela, le polymorphisme