Interfaces C++ (classes abstraites)
Une interface décrit le comportement ou les capacités d’une classe C++ sans pour autant imposer une implémentation spécifique à cette dernière.
Les interfaces C++ sont faites à l’aide des classes abstraites.
Nous sommes faces à une classe abstraite dès qu’une des fonctions est déclarée virtuelle pure. Une fonction est virtuelle lorsqu’on ajoute « =0 » après sa déclaration.
Ci-dessou, voici un exemple de déclaration d’une méthode virtuelle pure :
1 2 3 4 5 6 7 8 9 10 | class polygone // classe abstraite { public: /* fonction virtuelle pure */ virtual int getAire() = 0; protected: int largeur; int hauteur; }; |
L’objectif d’une classe abstraite est de fournir aux autres classes une classe de base appropriée dont elles pourront hériter. Les classes abstraites ne peuvent être instanciées, ni servir seulement d’interface. Tenter d’instancier un objet à partir d’une classe abstraite cause une erreur de compilation.
L’objet d’une classe abstraite est de fournir une classe de base appropriée à partir de laquelle les autres classes pourront hériter. Les classes abstraites ne peuvent pas être utilisées pour instancier des objets. Si vous essayez d’instancier un objet à partir d’une classe abstraite, vous aurez une erreur de compilation.
Par conséquent, si vous souhaitez instancier la sous classe (d’une classe abstraite) il est nécessaire que vous implémentiez chacune des fonctions virtuelles. Sinon vous aurez une erreur de compilation.
On appelle classes concrètes les classes pouvant être utilisées pour instancier des objets.
Exemple d’une Classe Abstraite
Considérons l’exemple suivant dans lequel une classe mère fournit une interface à la classe de base pour implémenter une fonction appelée getSurface().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | #include <iostream> #include <math.h> using namespace std; /* Classe de Base */ class Figure { public : /* fonction virtuelle pure */ virtual int getSurface() = 0; void setLargeur(int l) { largeur = l; } void setHauteur(int h) { hauteur = h; } protected : int largeur; int hauteur; }; // Classes dérivées class rectangle : public Figure { public : int getSurface() { return (largeur * hauteur); } }; class triangle : public Figure { public : int getSurface() { return (largeur * hauteur)/2; } }; int main(void) { rectangle un_rectangle; triangle un_triangle; un_rectangle.setLargeur(5); un_rectangle.setHauteur(7); cout << "Aire rectangle : " << un_rectangle.getSurface() << endl; un_triangle.setLargeur(5); un_triangle.setHauteur(7); cout << "Aire triangle : " << un_triangle.getSurface() << endl; return 0; } |
Lorsque le code ci-dessus est compilé et exécuté il produit le résultat suivant :
1 2 | Aire rectangle : 35 Aire triangle : 17 |
Vous pouvez voir dans l’exemple ci-dessus comment une classe abstraite définit une interface avec getSurface() et comment deux autres classes implémentent cette même fonction mais avec un algorithme différent pour calculer la surface spécifique à la forme géométrique.
Stratégie de conception
Une architecture orientée objet doit utiliser des classes de base abstraites pour fournir des interfaces standards et communes aux applications utilisatrices.
Donc, par héritage de ces classe abstraites, les classes dérivées sont construites pour fonctionner toutes de la même façon.
Les possibilités (e.g. fonctions publiques) offertes aux fonctions externes sont fournies en tant que méthodes virtuelles pures dans la classe de base abstraite. Les implémentations de ces méthodes virtuelles pures sont fournies dans les classes dérivées qui sont conformes au genre spécifique du programme.
De plus cette architecture permet à de nouvelles fonctions d’être ajoutées facilement au système.