Chapitre 4 – Le polymorphisme
Document réservé
Vous consultez actuellement la présentation publique de ce chapitre.
Les documents PDF complets, comprenant les développements théoriques, les exemples détaillés et les exercices, sont disponibles sur demande.
Pour obtenir un accès, contactez-moi via la page Contact en indiquant les domaines qui vous intéressent (C++, ESP-IDF, électronique, etc.).
4.1 Un même service, plusieurs comportements . . . . . . . . . . . . . . . . . . . . . . . .
4.2 Une fonction capable de recevoir n’importe quelle forme . . . . . . . . . . . . . . . .
4.2.3 Choisir la méthode d’après l’objet réel . . . . . . . . . . . . . . . . . . . . . .
4.3.1 override permet au compilateur de vérifier . . . . . . . . . . . . . . . . . . .
4.3.2 virtual et override ont des rôles différents . . . . . . . . . . . . . . . . . .
4.4 Liaison statique et liaison dynamique . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.5 Pointeurs et références polymorphes . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.5.3 Référence ou pointeur ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.6 Classes abstraites et fonctions virtuelles pures . . . . . . . . . . . . . . . . . . . . . .
4.6.1 Une méthode qui n’a pas de définition générale . . . . . . . . . . . . . . . . .
4.6.2 Une fonction virtuelle pure . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.6.4 Les classes dérivées fournissent l’implémentation . . . . . . . . . . . . . . . .
4.6.5 Une classe abstraite peut toujours être utilisée par référence . . . . . . . . .
4.7.1 Quel destructeur doit être appelé ? . . . . . . . . . . . . . . . . . . . . . . . .
4.7.2 Rendre le destructeur virtuel . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.7.3 Un destructeur virtuel par défaut . . . . . . . . . . . . . . . . . . . . . . . . .
4.8 Une collection de formes différentes . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.8.1 Un tableau de pointeurs vers la classe de base . . . . . . . . . . . . . . . . . .
4.8.2 Un même appel pour des objets différents . . . . . . . . . . . . . . . . . . . .
4.8.3 Le choix est confié à l’objet . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.8.4 Ajouter de nouvelles classes . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.8.5 Les pointeurs ne possèdent pas les objets . . . . . . . . . . . . . . . . . . . .
2026 – C++ Partie II
AccueilUn même service, plusieurs comportements Dans le chapitre précédent, nous avons vu que l’héritage permet de construire des classes spécialisées à partir d’une classe plus générale. Nous allons maintenant nous intéresser à une autre situation. Considérons différentes figures géométriques, par exemple un carré et un disque. Ces deux objets sont de nature différente, mais ils possèdent une caractéristique commune : il est possible de calculer Pour un carré de côté c , alors que pour un disque de rayon r , L’opération demandée est donc la même : mais le calcul nécessaire pour obtenir le résultat dépend de la nature de l’objet. Nous pouvons représenter les différentes figures à l’aide d’une classe générale appelée Forme. Nous construirons dans un premier temps deux classes dérivées : Un carré est une forme et un disque est également une forme. Les deux classes dérivées posséderont une méthode portant le même nom : double aire() const; mais chacune devra effectuer un calcul différent. Commençons par déclarer la classe de base : 2026 – C++ Partie II double aire() const; Cette classe ne contient pour l’instant aucune donnée. Elle possède simplement une méthode aire() commune aux formes que nous allons étudier. Nous devons cependant donner provisoirement une définition à cette méthode : double Forme::aire() const La valeur retournée n’a ici aucune signification géométrique. Une forme générale ne possède en effet ni côté ni rayon permettant de calculer son aire. Cette définition nous servira uniquement à observer le comportement du programme avant d’introduire les mécanismes propres au polymorphisme. Les classes Carre et Disque définissent chacune leur propre méthode aire(). double Carre::aire() const double Disque::aire() const return PI * rayon * rayon; Nous avons donc trois méthodes possédant la même signature : double aire() const; mais définies dans trois classes différentes. Considérons maintenant : std::cout << C.aire() << std::endl; std::cout << D.aire() << std::endl;
Accueil2026 – C++ Partie II Dans le premier appel, l’objet C est connu comme un Carre. La méthode utilisée est donc Dans le second, l’objet D est connu comme un Disque. La méthode utilisée est Tout fonctionne donc exactement comme prévu. Quoique ! Une question se pose cependant. Puisque Carre et Disque sont tous les deux des Forme, pouvons-nous écrire une seule fonction capable de recevoir n’importe quelle forme et de calculer automatiquement l’aire correspondant à l’objet réellement reçu ? Une fonction capable de recevoir n’importe quelle forme Nous souhaitons maintenant écrire une fonction unique capable de recevoir différents objets dérivés Pour éviter toute copie de l’objet, nous utilisons un passage par référence constante : void afficherAire(const Forme& forme) std::cout << forme.aire() Cette fonction peut recevoir aussi bien un objet de type Carre qu’un objet de type Disque, puisque ces deux classes dérivent de Forme. aucune copie de C n’est effectuée.
Accueil2026 – C++ Partie II désigne directement l’objet C, mais celui-ci est vu à travers le type de la classe de base Forme. Il en va de même pour l’objet D. Cependant, avec la version actuelle de notre programme, la méthode est choisie à partir du type de la référence forme, c’est-à-dire Forme. La méthode appelée est donc : Comme cette méthode retourne provisoirement 0.0, le programme affiche : Les objets transmis à la fonction sont pourtant réellement un Carre et un Disque. Pourquoi le programme n’appelle-t-il pas automatiquement Carre::aire() et Disque:: Dans notre version actuelle, le choix de la méthode est effectué à partir du type statique de la référence utilisée pour l’appel. Le paramètre forme étant de type const Forme&, la méthode Forme::aire() est sélectionnée. Nous allons maintenant modifier ce comportement afin que la méthode appelée dépende du type réel Reprenons la fonction générale construite précédemment : void afficherAire(const Forme& forme) std::cout << forme.aire() Le passage s’effectue par référence constante. L’objet transmis à la fonction n’est donc pas copié.
Accueil2026 – C++ Partie II l’objet réel reste un Carre, mais il est manipulé dans la fonction à travers une référence de type l’objet réel reste un Disque, mais il est également manipulé à travers une référence de type const Dans notre première version, la classe Forme contient : double aire() const; Lorsque l’instruction est exécutée, le choix de la méthode est effectué à partir du type de la référence utilisée pour l’appel. Cette référence étant de type Forme, la méthode appelée est donc même lorsque l’objet réel est un Carre ou un Disque. Dans notre exemple, cette méthode retourne provisoirement zéro. Les appels Choisir la méthode d’après l’objet réel Nous souhaitons au contraire que le programme tienne compte du type réel de l’objet désigné par la référence. Pour cela, la méthode est déclarée virtual dans la classe de base : virtual double aire() const; Le mot-clé virtual indique que le choix de la méthode doit pouvoir être effectué en fonction du type réel de l’objet lorsque celui-ci est manipulé à travers une référence ou un pointeur vers une
Accueil2026 – C++ Partie II Nous ne modifions rien dans la fonction : void afficherAire(const Forme& forme) std::cout << forme.aire() utilisent maintenant respectivement car les objets réellement désignés par la référence sont respectivement un Carre et un Disque. Pour un carré de côté 3 et un disque de rayon 2, le programme affiche : • Sans virtual, le choix de la méthode est effectué d’après le type statique de la référence ou du pointeur utilisé pour l’appel. • Avec virtual, le programme peut choisir la méthode d’après le type réel de l’objet désigné par cette référence ou ce pointeur. • Le passage par référence est essentiel ici : aucune copie de l’objet n’est effectuée et son type réel est conservé. Le mot-clé override La classe de base Forme déclare maintenant la méthode virtuelle : virtual double aire() const; Les classes dérivées possèdent leur propre version de cette méthode. Dans Carre, nous pouvons double aire() const override; double aire() const override;
Accueil2026 – C++ Partie II Le mot-clé override indique au compilateur que cette méthode doit redéfinir une méthode virtuelle héritée de la classe de base. override permet au compilateur de vérifier Considérons la déclaration correcte : double aire() const override; Elle correspond bien à la méthode de la classe de base : virtual double aire() const; Supposons maintenant que nous oubliions par erreur le mot-clé const : double aire() override; La signature n’est plus identique à celle de la méthode virtuelle définie dans Forme. Grâce à override, le compilateur détecte immédiatement le problème et signale que cette méthode ne redéfinit pas la méthode virtuelle attendue. Sans override, cette erreur serait beaucoup moins évidente : le programmeur pourrait croire qu’il a redéfini la méthode virtuelle alors qu’il a en réalité déclaré une méthode différente. virtual et override ont des rôles différents Les deux mots-clés ne sont donc pas synonymes. Dans la classe de base : virtual double aire() const; virtual demande un choix dynamique de la méthode. Dans une classe dérivée : double aire() const override; override demande au compilateur de vérifier que cette méthode redéfinit effectivement une méthode virtuelle héritée. • virtual est placé dans la classe de base pour permettre le choix dynamique de la • override est utilisé dans une classe dérivée pour indiquer qu’une méthode redéfinit une méthode virtuelle héritée. • override permet au compilateur de vérifier que la signature de la méthode correspond bien à celle de la méthode virtuelle. • Une différence telle que l’oubli de const suffit à produire une signature différente.
Accueil2026 – C++ Partie II Liaison statique et liaison dynamique Nous venons d’observer deux comportements différents selon que la méthode aire() est déclarée ou non virtual. Ces deux mécanismes portent des noms précis : • la liaison statique ; • la liaison dynamique. Le terme liaison désigne ici le mécanisme qui associe un appel de fonction à la fonction qui sera effectivement exécutée. Considérons tout d’abord une méthode non virtuelle : double aire() const; void afficherAire(const Forme& forme) std::cout << forme.aire() Le paramètre forme est déclaré comme une référence vers un objet de type Forme : Lorsque aire() n’est pas virtuelle, le choix de la méthode est effectué à partir de ce type. est donc associé à Cette association peut être déterminée lors de la compilation. On parle alors de liaison statique. le type déclaré de forme est
Accueil2026 – C++ Partie II Ce type est appelé type statique. Il est connu par le compilateur avant l’exécution du programme. Ainsi, sans méthode virtuelle, les appels conduisent tous les deux à l’utilisation de même si les objets transmis sont réellement un Carre et un Disque. La liaison dynamique Déclarons maintenant la méthode virtuelle : virtual double aire() const; Les classes dérivées redéfinissent cette méthode : double aire() const override; La fonction afficherAire() reste exactement la même : void afficherAire(const Forme& forme) std::cout << forme.aire() Cette fois, le choix de la méthode ne dépend plus uniquement du type statique de la référence. Le programme tient compte du type réel de l’objet désigné par cette référence. l’objet réel est un Carre. La méthode appelée est donc l’objet réel est un Disque. La méthode appelée est donc
Accueil2026 – C++ Partie II Le choix dépend donc de l’objet réellement présent lors de l’exécution du programme. On parle de la référence forme possède toujours le type statique mais l’objet réellement désigné est un Carre. Le type réel de cet objet est appelé ici son type dynamique. De même, lors de le type statique de la référence est toujours Forme, alors que le type dynamique de l’objet est Disque. Nous pouvons résumer les deux mécanismes de la manière suivante : méthode non virtuelle choix déterminable à la compilation choix selon l’objet à l’exécution • La liaison associe un appel de méthode à la méthode qui sera effectivement exécutée. • Avec une méthode non virtuelle, le choix dépend du type statique de l’expression utilisée pour effectuer l’appel. On parle de liaison statique. • Avec une méthode virtuelle appelée à travers une référence ou un pointeur de base, le choix tient compte du type réel de l’objet. On parle de liaison dynamique. • Une référence de type Forme& peut donc désigner un objet dont le type réel est Carre, Disque ou une autre classe dérivée de Forme. Pointeurs et références polymorphes Jusqu’à présent, nous avons utilisé une référence vers la classe de base : void afficherAire(const Forme& forme) std::cout << forme.aire() Cette référence peut désigner un objet de type Carre, Disque ou toute autre classe dérivée de Forme. Le polymorphisme fonctionne également avec un pointeur vers la classe de base.
Accueil2026 – C++ Partie II Avec une référence Les références F1 et F2 possèdent toutes deux le type statique Forme&. Cependant, elles désignent des objets dont les types dynamiques sont respectivement Carre et Disque. Si la méthode aire() est virtuelle, std::cout << F1.aire() << std::endl; std::cout << F2.aire() << std::endl; appelle respectivement Le même mécanisme peut être utilisé avec des pointeurs : Cette fois, F1 et F2 contiennent l’adresse des objets. L’appel d’une méthode s’effectue avec l’opérateur −> : std::cout << F1->aire() << std::endl; std::cout << F2->aire() << std::endl; Comme aire() est virtuelle, le programme tient compte du type dynamique de l’objet pointé. Les méthodes appelées sont donc à nouveau Référence ou pointeur ? Les deux écritures suivantes permettent donc le polymorphisme : Forme& reference = C; Forme* pointeur = &C; Dans le premier cas, l’appel s’écrit :
Accueil2026 – C++ Partie II Une référence doit désigner un objet lors de son initialisation et ne peut pas être réaffectée pour désigner un autre objet. Un pointeur peut en revanche recevoir successivement différentes adresses. • Le polymorphisme dynamique fonctionne avec des références ou des pointeurs vers une • Une référence utilise l’opérateur . pour appeler une méthode. • Un pointeur utilise l’opérateur −>. • Dans les deux cas, si la méthode est virtuelle, la version appelée est déterminée d’après le type dynamique de l’objet. • Une référence reste liée au même objet après son initialisation, alors qu’un pointeur peut être modifié pour désigner un autre objet. Classes abstraites et fonctions virtuelles pures Jusqu’à présent, notre classe de base Forme possède une méthode virtuelle : virtual double aire() const; Pour pouvoir effectuer nos premières expériences sur le polymorphisme, nous avions donné à cette méthode une définition provisoire : double Forme::aire() const Cette solution nous a permis d’observer le comportement du programme avant et après l’introduction du mot-clé virtual. Elle présente cependant un problème de conception. Une méthode qui n’a pas de définition générale Pour un carré, le calcul de l’aire est parfaitement défini :
Accueil2026 – C++ Partie II Mais que devrait calculer la méthode pour une forme générale ? La classe Forme ne contient aucune information permettant d’effectuer ce calcul. Retourner arbitrairement n’est pas une solution satisfaisante. La valeur zéro représente en effet une valeur numérique parfaitement valide. Rien ne permettrait de distinguer cette valeur d’un véritable résultat. Ce que nous souhaitons exprimer est différent : Toute forme doit posséder une méthode permettant de calculer son aire, mais il n’existe pas de calcul général de cette aire dans la classe Forme. Le C++ permet d’exprimer directement cette situation à l’aide d’une fonction virtuelle pure. Une fonction virtuelle pure Une fonction virtuelle pure est déclarée en ajoutant Notre classe Forme devient donc : virtual double aire() const = 0; Attention : le symbole ne signifie absolument pas que la fonction retourne la valeur zéro. Il indique que aire() est une fonction virtuelle pure. Une classe abstraite Une classe contenant au moins une fonction virtuelle pure est une classe abstraite. Il n’est plus possible de créer directement une instance de Forme :
Accueil2026 – C++ Partie II Cette interdiction est logique : une Forme générale ne contient pas suffisamment d’informations pour La classe Forme reste cependant parfaitement utilisable comme classe de base. Les classes dérivées fournissent l’implémentation La classe Carre fournit sa propre version de la méthode : class Carre : public Forme Carre(double coteInitial); double aire() const override; double Carre::aire() const De même, la classe Disque fournit : double aire() const override; double Disque::aire() const return PI * rayon * rayon; La classe Forme ne fournit donc plus le calcul de l’aire. Elle impose simplement une propriété commune aux classes qui représentent des formes concrètes : une forme concrète doit savoir calculer son aire. Chaque classe dérivée décide ensuite de la manière dont ce calcul doit être effectué. Une classe abstraite peut toujours être utilisée par référence Bien qu’il soit impossible de construire directement un objet de type Forme, une référence vers Forme reste parfaitement valable.
Accueil2026 – C++ Partie II void afficherAire(const Forme& forme) std::cout << forme.aire() ne doit donc pas être modifiée. Nous pouvons toujours écrire : La référence forme désigne successivement un objet Carre puis un objet Disque. Grâce à la liaison dynamique, les méthodes sont respectivement utilisées. • Une fonction virtuelle pure est déclarée à l’aide de la syntaxe : virtual double aire() const = 0; • Le symbole = 0 ne représente pas une valeur retournée par la fonction. Il indique que la fonction est virtuelle pure. • Une classe contenant au moins une fonction virtuelle pure est une classe abstraite. • Il n’est pas possible de créer directement une instance d’une classe abstraite. • Une classe abstraite peut cependant être utilisée comme classe de base et être manipulée à travers des références ou des pointeurs. • Une classe dérivée qui doit devenir concrète fournit une implémentation des fonctions virtuelles pures héritées. Le mot-clé override permet de faire vérifier cette redéfinition
Accueil2026 – C++ Partie II Le destructeur virtuel Le polymorphisme permet à un pointeur vers une classe de base de désigner un objet appartenant à une classe dérivée. Forme* forme = new Carre(3.0); Le type du pointeur est mais l’objet réellement construit avec new est un Carre. Grâce à la méthode virtuelle aire(), l’instruction appelle correctement Le type réel de l’objet est donc pris en compte lors de l’appel de la méthode. Une question importante apparaît cependant lorsque nous voulons détruire cet objet. Quel destructeur doit être appelé ? L’objet ayant été créé avec new, nous devons finalement le détruire avec : Mais le pointeur forme est de type Forme*, alors que l’objet réellement présent en mémoire est un Carre. Nous devons donc nous demander quel destructeur doit être exécuté. Pour détruire correctement l’objet complet, nous voulons obtenir : Carre:: Carre() −→ Forme:: Forme() La destruction doit commencer par la classe la plus spécialisée puis remonter la hiérarchie. Rendre le destructeur virtuel Lorsqu’un objet d’une classe dérivée doit pouvoir être détruit à travers un pointeur vers sa classe de base, le destructeur de la classe de base doit être déclaré virtual. Nous écrivons donc : virtual double aire() const = 0;
Accueil2026 – C++ Partie II Un destructeur virtuel par défaut Si le destructeur de la classe de base ne doit effectuer aucune opération particulière, nous pouvons demander au compilateur de fournir son implémentation : virtual ~Forme() = default; Le destructeur reste virtuel, mais nous n’avons pas besoin d’en écrire manuellement la définition. Cette écriture est particulièrement adaptée à notre classe Forme. • Un objet d’une classe dérivée peut être manipulé à travers un pointeur vers sa classe de • Si cet objet doit être détruit avec delete à travers ce pointeur de base, le destructeur de la classe de base doit être virtuel. • Un destructeur virtuel garantit que la destruction commence par la classe correspondant au type réel de l’objet puis remonte la hiérarchie. • Si le destructeur n’a aucun travail particulier à effectuer, on peut écrire : virtual ~Forme() = default; Une collection de formes différentes Le polymorphisme devient particulièrement utile lorsque plusieurs objets appartenant à des classes différentes doivent être traités de manière uniforme. Considérons plusieurs objets : Ces objets n’ont pas tous le même type mais possèdent cependant une classe de base commune : Nous pouvons donc utiliser des pointeurs vers cette classe de base pour désigner chacun de ces objets.
Accueil2026 – C++ Partie II Un tableau de pointeurs vers la classe de base Déclarons un tableau contenant des pointeurs vers Forme : Les quatre éléments du tableau possèdent exactement le même type : Nous pouvons cependant leur affecter les adresses d’objets appartenant à différentes classes dérivées : Nous obtenons donc schématiquement : Le type statique de chaque élément du tableau est Forme*, mais le type dynamique de l’objet pointé peut être différent. Un même appel pour des objets différents Nous pouvons maintenant parcourir le tableau : for (int i = 0; i < 4; i++) std::cout << formes[i]->aire() La même instruction est exécutée à chaque passage dans la boucle. Pourtant, la méthode réellement appelée dépend de l’objet désigné par le pointeur et nous obtenons Le programme n’a besoin d’aucun test permettant de déterminer explicitement la nature de chaque
Accueil2026 – C++ Partie II Le choix est confié à l’objet Le programme qui parcourt la collection n’a pas besoin de savoir si l’objet rencontré est un carré ou Il demande simplement : La liaison dynamique sélectionne ensuite automatiquement la méthode correspondant au type réel C’est l’un des intérêts essentiels du polymorphisme : le programme peut manipuler différents objets à travers une interface commune sans devoir tester explicitement leur type. Ajouter de nouvelles classes Supposons que nous ajoutions maintenant une nouvelle classe Triangle dérivée de Forme. Si cette classe fournit correctement double aire() const override; un pointeur Forme* peut également désigner un objet de cette nouvelle classe. La boucle qui traite la collection n’a pas besoin de connaître Triangle et son principe ne doit pas être modifié. Elle continue simplement à exécuter : La classe de l’objet détermine elle-même la version de aire() qui sera exécutée. Les pointeurs ne possèdent pas les objets Dans cet exemple, les objets ont été créés directement : Le tableau contient uniquement leurs adresses : Aucune allocation dynamique n’a été effectuée avec new. Il ne faut donc pas utiliser delete sur ces pointeurs car les objets C1 et D1 seront détruits automatiquement lorsqu’ils atteindront la fin de leur durée de vie.
Accueil2026 – C++ Partie II • Un pointeur vers une classe de base peut désigner un objet appartenant à une classe • Un tableau de pointeurs vers une classe de base peut donc désigner des objets appartenant à plusieurs classes dérivées différentes. • Le type statique des pointeurs reste identique, mais le type dynamique des objets pointés • Lorsqu’une méthode est virtuelle, le même appel peut provoquer des comportements différents selon le type dynamique de l’objet. • L’ajout d’une nouvelle classe dérivée ne nécessite pas de modifier le principe de la boucle qui traite les objets à travers l’interface commune. • Un pointeur contenant l’adresse d’un objet qui n’a pas été créé avec new ne doit pas être utilisé avec delete L’héritage étudié au chapitre précédent permet de construire une nouvelle classe à partir d’une classe existante. Le polymorphisme va plus loin : il permet de manipuler des objets de classes différentes à travers une même classe de base tout en conservant leur comportement propre. Dans notre exemple, les classes Carre, Disque et Triangle dérivent toutes de la classe Forme. Elles possèdent une même méthode : double aire() const; mais chacune en fournit une implémentation différente. virtual double aire() const = 0; dans la classe Forme permet à cette méthode d’être choisie dynamiquement en fonction du type réel Nous pouvons ainsi écrire : et placer dans ce tableau les adresses d’objets appartenant à différentes classes dérivées. Une seule instruction suffit alors pour calculer l’aire de chacun d’eux : Le code qui parcourt la collection n’a pas besoin de déterminer lui-même si l’objet rencontré est un carré, un disque ou un triangle. Cette responsabilité est confiée au mécanisme de liaison dynamique. Le polymorphisme permet ainsi de séparer deux problèmes :
Accueil2026 – C++ Partie II • le programme utilisant les objets demande une opération commune ; • chaque classe spécialisée définit la manière dont cette opération doit être réalisée. Cette séparation permet notamment d’ajouter de nouvelles classes dérivées sans modifier le principe du code qui manipule les objets à travers leur classe de base. • Une méthode déclarée virtual peut être sélectionnée en fonction du type dynamique • Le mot-clé override permet de vérifier qu’une méthode redéfinit correctement une méthode virtuelle héritée. • Une fonction virtuelle pure est déclarée avec = 0. Une classe qui contient une telle fonction est abstraite. • Une classe abstraite ne peut pas être instanciée directement, mais elle peut servir de type commun pour des références et des pointeurs. • Le polymorphisme dynamique nécessite de conserver l’objet réel. Il s’utilise donc notamment à travers des références ou des pointeurs vers la classe de base. • Lorsqu’un objet dérivé peut être détruit avec delete à travers un pointeur vers la classe de base, le destructeur de cette classe doit être virtuel. • Une collection de pointeurs vers une classe de base peut désigner des objets appartenant à différentes classes dérivées. Un même appel de méthode peut alors produire des comportements différents selon l’objet rencontré.
AccueilP2-Chap-04- Le polymorphisme
AccueilTermes à ajouter au glossaire
Codes et programmes contenus dans le chapitre
Aire v.1.0
Classe Forme initiale
Aire v.2.0
Classe Forme et polymorphisme du calcul de l’aire de formes héritées de Forme
README.pdf
Explications sur l’utilisation des codes