Table des matières
Programmation Orientée Objet (POO)
Formation
La POO est très utilisée pour obtenir des codes clairs et efficaces, et c’est aussi la façon courante de coder en C++.
Dans une première partie on apprendra la POO sous Python afin d’utiliser un langage déjà bien connu. On verra ensuite la syntaxe adaptée au C++ afin de pouvoir transposer ce que l’on aura appris.
I - Petite introduction à la POO
Le principe de la POO est de définir un objet, auquel on peut ensuite :
- associer des valeurs que l’on appellera attributs.
C’est l’équivalent des caractéristiques de l’objet. Ils peuvent être définis lors de la création de l’objet, et l’on peut en rajouter ou les modifier lors de son utilisation.
- mais aussi des fonctions qui lui seront propre, appelées méthodes.
C’est l’équivalent des actions possibles de l’objet.
Pour créer ces objets on utilise des classes. Une classe et l’équivalent d’un moule pour un objet : on définit la classe en listant les attributs et les méthodes que l’on veut donner à nos objets. On pourra par la suite créer des objets à partir de ce moule, afin de les manipuler selon nos règles prédéfinies.
Notre exemple sera la création d’un personnage de jeu vidéo. Ce dernier aura divers attributs :
- Vie
- Mana
- Stamina
- …etc…
Et divers méthodes :
- Esquiver
- Lancer un sort
- Boire une potion
- …etc…
II - Premiers pas en POO
Un espace de travail propre
Le code que l’on va implémenter dans ce TP sera composé de plusieurs fichiers Python dans un même répertoire :
- Un fichier “main.py” dans lequel on utilisera les classes créées ailleurs.
- Des fichiers du format “nom_classe.py” pour chaque classe que l’on créera.
Définir une classe
Syntaxe : Le mot clé pour définir une classe est class (def est le mot clé pour définir une fonction)
# Dans le fichier "personnage.py" class Personnage: pass # "pass" dit à Python de ne rien faire
Nous pouvons maintenant créer des objet de la classe Personnage comme suit :
# Dans le fichier "main.py" from personnage import * mario = Personnage() # mario est une instance de Personnage
On appelle l'objet mario une instance de Personnage.
Utiliser les attributs et méthodes
Pour accéder à un attribut, on utilise la syntaxe :
nom_objet.nom_attribut
Pour utiliser une méthode, on utilise la syntaxe :
nom_objet.nom_methode(arguments)
Remarque : Notre Mario n’a ni attribut, ni méthode pour l’instant…
Donner des attributs
On utilise la syntaxe init(self) qui est une fonction qui se lancera lors de la création de l’objet.
class Personnage: def __init__(self): self.vie = 100 self.mana = 50 self.stamina = 100
Exercice : Afficher les différents attributs de votre Mario.
Nous voulons que notre objet ait un attribut nom qu’on lui donne lors de l’initialisation. Pour cela, on utilise la syntaxe :
class Personnage: def __init__(self, nom): self.nom = nom
Lors de la création de notre instance mario, il faut donc maintenant préciser son nom :
mario = Personnage("Mario")
Créer des méthodes
Les méthodes prennent obligatoirement en argument self, qui est l’objet lui même. Lors de l’appel de la méthode, on ne précise pas ce qu’est self car c’est par défaut l’objet en question.
Pour créer une méthode, il faut définir une fonction dans la définition de votre classe. Créons la méthode esquiver qui :
- enregistre True dans un attribut esquive si le personnage a assez de stamina pour esquiver (disons 20).
- enregistre False sinon.
Héritage, qu’est-ce que c’est ?
Nous avons défini Mario comme étant une instance de Personnage, mais au vu de ce que sait faire Mario (lancer des boules de feu, changer de forme, …etc…), Mario est un mage ! On voudrait donc pouvoir imaginer que l’on ait plusieurs types de personnages :
- mage
- guerrier
- …etc…
Tous ces types ont les caractéristiques de bases d’un Personnage, et en plus possèdent des spécificités.
La POO permet de créer des classes qui héritent des attributs et méthodes de classes définies auparavant. Dans notre cas, Mage est une sous-classe de Personnage.
Pour créer une sous-classe héritant d’une autre classe on écrit :
class Mage(Personnage): pass # "pass" dit à python de ne rien faire
Vous pouvez définir votre mario comme une instance de Mage() maintenant. Les commandes réalisées précédemment sont alors toujours fonctionnelles ! Vous pouvez essayer.
Priorité sur l’héritage : Si vous définissez un attribut ou une méthode dans la sous-classe qui ait le même nom qu’un attribut ou une méthode de la classe dont elle hérite, c’est la définition de la sous-classe qui l’emporte.
III - Un peu de pratique
Enoncé
Il est temps d’étoffer votre code. Réalisez les tâches suivantes :
- Personnage() :
- Un personnage apparaît avec 2 potions.
- Afficher le statut d’un personnage sur une ligne (vie, mana, stamina, potions)
- Boire une potion lui régénère 70 PV.
- Il peut mourir dans un cri effroyable.
- Il peut prendre des dégâts, mais l’esquive permet de passer outre.
- Il peut se concentrer pour récupérer 30 mana.
- Mage(Personnage):
- Peut lancer un sort qui fait 35 dégâts à un Personnage, et coûte 20 mana.
- Guerrier(Personnage) :
- Peut frapper un Personnage, ce qui fait 15 dégâts et coûte 5 mana.
- Peut frapper violemment, ce qui lui fait 15 dégâts, et 50 dégâts à un Personnage.
- Faire combattre Mario (un mage) contre Luigi (un Guerrier):
- Utiliser toutes les méthodes possible.
- Finir sur la mort d’au moins un des deux.
Aide
Solutions
IV - Syntaxe C++
La syntaxe en C++ est bien différente, et certains principes changent. Étant moins à l’aise en C++, je reconnais m’être complètement inspiré du site suivant. N’oubliez pas, pour coder vous pouvez tout trouver sur internet !
https://fr.wikibooks.org/wiki/Programmation_C%2B%2B/Les_classes
Et si vous n’avez pas d’IDE actuellement, je vous invite à en utiliser un en ligne, comme le suivant par exemple :
https://www.onlinegdb.com/online_c_compiler
Nous allons donc créer une classe point, qui contient des coordonnées et différentes fonctions de calcul avec d’autres points. Commençons !
Les fichiers
En C++, on garde les bonnes habitudes et on présente bien. Il nous faudra donc un fichier ‘header’ du nom de point.h, c’est le fichier d’entête dans lequel seront listés les attributs et méthodes de l’objet. Un second fichier du nom de point.cpp, c’est le fichier source dans lequel seront contenues les méthodes. Et tant qu’à faire, un fichier où tester tout ça, main.cpp.
Principes de bases
La POO en C++ va s’appuyer sur des principes utilisable en Python, mais très fortement conseillé en C++.
Ainsi toute méthode ou tout attribut pourra être définie comme :
- public : dans ce cas on peut y accéder en dehors de la classe en les appelants.
- private : dans ce cas les appels ne fonctionnent qu’au sein de la classe.
- protected : comme private, mais les classes qui en hérite y on accès.
L’objectif est de protéger les attributs pour qu’ils ne soient pas modifier à tort. On doit alors créer des ‘getter’ et des ‘setter’ pour lire et modifier ces attributs. Ce sont des méthodes appelables en dehors de la définition de l’objet (donc publiques), qui pourront accéder aux attributs ‘private’ depuis l’intérieur de l’objet.
Tout comme la méthode _init()_ en Python, on peut (doit) définir un ou plusieurs constructeurs selon si l’on utilise des arguments.
À vous
Pour finir, après avoir pris connaissance de la syntaxe utilisé dans l'exemple, vous allez implémenter deux méthodes :
- distance : qui renvoie la distance du point considéré à un autre point.
- milieu : qui renvoie le point milieu entre le point considéré et un autre point.