Le TP de la semaine dernière était très dense. Terminez le TP précédent avant de faire celui-ci
Date de première publication : 2013/10/03
1. Petites vérifications
Avez-vous vérifié les choses suivantes ?
- que le passage d'un objet se fait par défaut par copie. Pour cela, il suffit de réutiliser
la classe
Bavarde
, de passer une variable à une fonction quelconque et de compter le nombre de destructions
- que le retour de méthode/fonction crée aussi une copie.
- Ajoutez maintenant un constructeur de copie à la classe
Bavarde
qui incrémentera le nombre d'instances et vérifer qu'il est bien appelé dans les situations précédentes - que l'utilisation d'une référence ne crée pas de copie,
- et l'utilisation d'un pointeur non plus
1.1. Troncature de type
Vérifier ce qu'est la troncature de type et comment on l'évite ...
2. Fil rouge ...
La base des deux exercices est clonable ici :
Vous avez écrit les classes Rectangle
et Cercle
. L'idée est de mettre désormais en place l'héritage pour qu'un rectangle (respectivement un cercle) soit une forme. Nous allons ajouter également la composition/agrégation avec la classe Point
2.1. Classe Point
Une instance particulière de la classe Point
, ORIGINE
sera définie et utilisée. Cette origine servira de référence quand la position de la forme ne sera pas précisée à la construction (une constante globale fait l'affaire).
Si vous voulez définir ORIGINE
comme un membre public constant de classe Point
, c'est tout-à-fait possible, modifiez les tests en conséquence. De l'intérieur de la classe, ORIGINE
est directement accessible. De l'extérieur, il faudra préfixer par le nom de la classe qui définit ce point particulier Point::ORIGINE
2.2. Classe Forme
Passons maintenant à la classe Forme
. Ajoutez un attribut couleur
de type COULEURS
. COULEURS
peut être une énumération classique (à la C) mais aussi une énumération typée (enum class), concept apparu avec la norme 2011 du langage.
Les enum class
ont de nombreux avantages par rapport aux énumérations classiques dont notamment la portée limitée des valeurs (on est obligé de préfixer la valeur par le nom de l'énumération) et la non conversion implicite en entier
Vous allez doter également la classe d'un attribut id
qui est un indentifiant unique de la forme (on s'appuiera sur l'attribut nbFormes
.
Nous ne devrions pas avoir besoin de publier cet attribut de classe (dans un usage normal de la classe) mais pour les tests, il va tout de même falloir le faire. La méthode associée s'appelle prochainId()
et permet un accès en lecture seulement de cet attribut.
2.3. Classes Rectangle
et Cercle
Écrivez la relation d'héritage entre les classes Rectangle
et Cercle
et la classe Forme
. Nettoyez les méthodes et attributs non nécessaires ! La création d'un rectangle ou d'un cercle doit incrémenter natuellement le compteur de formes.
On pourra ensuite vérifier le polymorphisme fort (les tests sont à adapter en fonction de ce que renvoient les méthodes toString()
)
La classe Forme
devra être abstraite et vous devrez choisir quelles méthodes sont virtuelles (pures ou non). Dès que la classe aura été modifiée pour être abstraite, les premiers tests avec instanciation ne seront plus utilisables (le compilateur n'acceptera plus leur compilation)
2.4. Classe Liste
Le code de la classe Liste
est maintenant bien plus facile à écrire !
Vous allez transformer la classe Liste
en une classe Groupe
. On aurait pu faire de l'héritage multiple mais on en l'a pas encore vu en cours, n'est-ce pas ?
Un groupe est une forme. Dans cette classe, le point, la largeur et la hauteur sont calculés comme étant ceux de la boîte englobante et mis à jour lors des opérations d'ajout et de suppression des formes au groupe. Le polymorphisme et l'upcasting permettent de vérifier que la relation d'héritage est correcte.
Le groupe peut servir à stocker une scène à afficher.
2.5. Aller plus loin...
Vous pouvez coder une interface texte qui répondra aux messages suivants
3. Une pincée de profilage
Voici un petit programme à analyser avec un profiler. On pourra par exemple compter le nombre de fois que certaines méthodes sont appelées
3.1. Rappel : gprof
Pour profiler avec gprof, il suffit :
- de compiler le programme avec l'option -pg.
- de lancer l'exécutable : cela génère un fichier gprof.out
- d'analyser le fichier en le donnant à gprof.
Note : un programme compilé avec l'option -pg est beaucoup plus long à s'exécuter.
3.2. Valgrind
Nous pouvons également utiliser ce couteau suisse de la programmation : valgrind. Il suffit pour cela de choisir un autre outil que celui par défaut (memcheck).
- Compiler avec l'option -g
- Exécuter
valgrind --tool=callgrind --dump-instr=yes executable
- Analyser les résultats avec
kcachegrind (installé sur les machines LINUX)
Note : valgrind utilise une simulation de processeur, l'exécution peut donc être 50 fois plus longue que le programme original, l'avantage est que le temps de calcul utilisateur ne dépend pas de la charge machine
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
