Travaux pratiques C++

Eric Lecolinet - Télécom ParisTech (ENST) - Dpt. INFRES

Liens utiles

Exercices

Le but de ces travaux pratiques est de créer un logiciel permettant de "gérer" l'ensemble des personnes étudiant ou travaillant à Télécom Paris. Ce logiciel sera réalisé par étapes, en començant par la conception et l'implémentation des classes principales, puis en rajoutant diverses fonctionnalités.

Etape préliminaire. Arbre d'héritage

Concevoir l'arbre d'héritage des classes principales sur papier en spécifiant les principales méthodes, données (et types de données) qui seront utilisées par ces classes.

On tiendra compte des remarques suivantes:

il y a 2 grandes catégories de personnes présentes à l'Ecole :

les caractéristiques typiques incluent :

les fonctionnalités principales incluent:

IMPORTANT : on se limitera ici à l'essentiel sans trop entrer dans les détails l'important étant de déterminer ce qui peut être factorisé pour faciliter le choix des classes et les relations d'héritage.

1e étape. Déclaration et implémentation de la classe Racine

a) Ecrire le header C++ (déclaration) de la classe Racine (on pourra trouver un nom plus adapté) de l'arbre d'héritage des classes. Cette classe se limitera à la gestion des coordonnées principales d'une personne : nom, prénom, age, email.

Déclarer les méthodes adéquates pour créer un objet de cette classe, modifier ou accèder à ses champs et afficher le contenu global de l'objet à l'écran (avec les intitulés correspondants).

Remarques:

b) Implementer cette classe (dans un fichier .cc). Le compiler avec g++ et corriger les (éventuelles !) erreurs de syntaxe.

c) Ecrire un petit programme de test qui crée un objet et permette d'initialiser ou modifier son contenu et de l'afficher à l'écran.

2e étape. Déclaration et implémentation de la classe Etudiant

a) Ecrire le header correspondant (utiliser des fichiers disctincts pour les diverses classes).
On prendra en compte: le type de cursus, la longueur du cursus, ainsi que l'année actuelle dans le cursus.

b) Ecrire et compiler le fichier d'implémentation correspondant puis tester les deux classes déjà implémentées. Pour ce faire, écrire un Makefile puis utiliser la commande make (on pourra s'inspirer de cet exemple de Makefile ; attention ne pas faire de coupé-collé (à cause des tabulations) mais sauvegarder via les commandes du navigateur).

3e étape. Déclaration et implémentation de la classe Employé

Même principe que précédemment, les caractéristiques d'un employé étant son département et son bureau.

4e étape. Gestion générique

On veut maintenant pouvoir gérer géneriquement une liste d'étudiants et d'employés. On commencera pour ce faire par utiliser un tableau de pointeurs que l'on initialisera de manière appropriée dans un programme de test.

Ecrire une fonction qui permette d'afficher le contenu complet de tous les éléments contenus dans la liste, quel que soit leur type (les informations disponibles n'étant pas les mêmes pour un étudiant ou un employé).
Cette fonction devra respecter le principe d'encapsulation (pas d'accès direct aux champs des objets par une fonction non-membre) et on évitera toute duplication inutile de code.

Comment s'appelle la propriété, caractéristique de l'OO que nous devrons employer ? Comment les méthodes doivent-elles être déclarées pour que cette propriété soit effective en C++ ?

Remarque : la gestion générique de la liste devra apparaître dans votre programme final (éventuellement sous une forme modifiée). Ne supprimez pas le code correspondant en faisant les questions suivantes !

5e étape. Déclaration et implémentation de la classe Eleve

On veut maintenant spécialiser la classe Etudiant en définissant la sous-classe Eleve. Une caractérisque des élèves est qu'ils suivent des UEs qui sont sanctionnées par des notes. Faire en sorte que l'on puisse associer une liste de notes à un élève (seulement les notes, pour simplifier on ne tiendra pas compte des noms des UEs).

Ces notes seront stockées dans l'"Eleve" en utilisant un tableau (pas un vecteur de la STL). On définira:

Remarques: Que faut-il faire pour éviter les problèmes de gestion mémoire et respecter les règles de l'encapsulation ?

Les autres sous-catégories d'Etudiants (pas déclaréees pour l'instant) peuvent aussi avoir des notes. Mais celles-ci ne sont pas calculées de la même manière (ils ne suivent pas forcement des UEs, etc.).

Rajouter à la classe Etudiant une méthode qui retourne la note globale. Son calcul étant indéfini au niveau de cette classe, utiliser une méthode abstraite. Qu'est-il alors nécessaire de faire dans les sous-classes de Etudiant ? Le faire dans le cas de la classe Eleve (en calculant la moyenne des notes du tableau).

La méthode d'affichage devra également afficher la moyenne et les différentes notes du tableau.

6e étape. Destruction

Contrairement à Java, C++ ne propose pas en standard de "garbage collector" pour récupérer la mémoire dynamique précédemment allouée et qui n'est plus utilisée (= qui n'est plus référencée par aucun pointeur).

Que faut-il faire pour détruire correctement les objets (sans fuite mémoire ni "segmentation fault" !). Rajoutez le code nécessaire et faites quelques tests mélangeant destruction et construction d'objets.

Question: les classes comportant des méthodes virtuelles doivent, logiquement, avoir des destructeurs virtuels. Pourquoi ?

7e étape. Constance et références

(Attention : cette question est importante : elle comprend 2 parties qui doivent être faites en même temps pour gagner du temps)

a) Vérifiez que vous avez correctement implémenté les règles de constance dans les classes déja réalisées. Citez les 3 cas de figures ou le mot-clé const doit être utilisé. Modifiez votre code en conséquence partout où c'est nécessaire.

b) Vérifiez également que vous avez utilisé le passage par référence des arguments des méthodes chaque fois que cela était nécessaire.

Question: comment imposer qu'un objet créé avec new soit à valeur constante (par exemple un objet de classe Eleve dans votre fonction main()). Que se passerait'il si on essayait de lui appliquer la methode qui change les notes d'un élève ? Même question pour la méthode qui permet d'afficher son contenu. Pourquoi ?

8e étape. Initialisation et affectation

Vos objets contiennent probablement des pointeurs (typiquement vers le tableau de notes). Il est donc dangereux de les recopier par simple affectation (les variables d'instances des 2 objets pointeraient vers les mêmes valeurs).

Questions:

Rajoutez le code correspondant dans vos classes.

9e étape. STL

Réécrire l'étape 4 en utilisant les vecteurs puis les listes chaînées de la STL.

10e étape. Entrées/sorties et fichiers

Rajouter les fonctionnalités d'entrées-sorties manquantes : lecture au clavier des champs des classes et lecture / écriture sur un fichier. Pensez à bien modulariser votre code et à respecter les principes de l'orienté objet.

Note: on pourra éventuellement utiliser des ofstream et des ifstrems (voir le lien Manuel des librairies C++ de Sun ou ... le Web!)

Question subsidiaire (bonus!)

Question libre : rajoutez toute fonctionnalité qui vous semblerait utile (comme par exemple la gestion des exceptions pour gérer les cas d'erreurs).

Rendu du TP

Pensez à utiliser la commande rendu-tp (SVP pas de rendu de TP par email !).
Algorithme:

   cd le-bon-repertoire
   # faire le menage (pas trop tout de même!)
   # penser a mettre un README
   rendu-tp inf224-cpp votre-login

Notez que cette commande copie également les sous-répertoires. Evitez de l'activer plusieurs fois (ou depuis un répertoire erroné ou avec un mauvais nom de login !)

Le fichier README doit indiquer les étapes réalisées et contenir les réponses aux questions correspondantes ainsi que les explications qui vous sembleront utiles (tout en restant concis : ce texte n'a pas besoin d'être très long).

Remarque: Ce fichier doit être en format texte standard ou en PDF. Evitez SVP:


home page page cours    Eric Lecolinet - ENST / INFRES - http://www.enst.fr/~elc