Vu le principe d'encapsulation, il est formellement interdit d'atteindre directement les attributs d'une classe. Il faut
systématiquement passer par une méthode. Cette technique est judicieuse puisque le changement d'état d'un objet passe d'abord par un
changement de comportement. Il existe des méthodes adaptées pour résoudre les initialisations explicites pour que l'objet soit dans
l'état désiré. Ces méthodes spécifiques s'appellent des constructeurs. La construction personnalisée des objets est très fréquente
alors que la destruction l’est beaucoup moins. Nous verrons, malgré tout, des cas où il est absolument nécessaire de redéfinir le
destructeur proposé par défaut. Avant cela, nous allons nous intéresser au pointeur this.
Liste des travaux pratiques
Gestion des notes en mode console
Vous allez mettre en œuvre un programme qui permet de gérer un ensemble de notes afin que, par la suite, il soit possible de
déterminer une moyenne, donner la note la plus petite, la plus grande, etc. Pour implémenter ce comportement, vous allez constituer
deux classes fondamentales, la première la classe Notes qui gère l'ensemble des calculs relatifs aux notes intoduites, la
deuxième Gestion s'occupe, comme son nom l'indique, de gérer l'ensemble du programme en mode console.
Fonctionnalités du programme - diagramme des cas d'utilisation
Grâce au diagramme des cas d'utilisation nous spécifions toutes les fonctionnalités attendues par le système de gestion des notes.
Ainsi, à tout moment, nous pouvons ajouter une nouvelle note, supprimer une ou toutes les notes déjà introduites. Quelquesoit
le choix effectué, nous visualisons systématiquement toutes les caractéristiques d'une gestion de notes : l'ensemble des notes, la
moyenne, la note maxi et la note mini.
Diagramme des classes
Afin de bien suivre les fonctionnalités attendues, je vous propose de respecter la structure suivante qui comme nous l'avons
évoqué lors de l'introduction est constituées de deux classes : la première la classe Notes qui gère l'ensemble des calculs
relatifs aux notes intoduites, la deuxième Gestion s'occupe, comme son nom l'indique, de gérer l'ensemble du programme en
mode console.
Dans la classe Gestion, remarquez bien que la plupart des méthodes sont privées sauf le constructeur et la
méthode run().Diagramme des composants
La description de ces deux classes se fera dans des fichiers associés, d'une part, les fichiers en-tête pour la déclaration des
deux classes et d'autre part les fichiers source pour la définition des méthodes correspondant à la classe.
Diagramme de séquence
Lecture du diagramme :
Au démarrage du programme, création de l'objet gestion avec en paramètre la valeur 10 demande de
gérer 10 notes.
Dès que l'objet est créé, nous avons également la création de l'objet notes attribut de Gestion.
Dès que les objets sont opérationnels, le programme principal appelle la méthode run() de l'objet gestion remarquez
que c'est tout ce que réalise le programme principal.
À l'intérieur de la méthode run(), la méthode privée menu() est d'abord sollicitée.
Quand le menu est affiché, c'est la méthode choisir(3) 3 correspond au nombre d'options disponibles dans le
menu qui est appelée à son tour. Cette dernière attend la saisie du numéro de la commande de la part de l'utilisateur.
L'utilisateur propose son choix. Il est alors nécessaire de vérifier si la valeur de ce choix correspond à une des options du
menu, sinon il faut redemander une nouveau choix à l'utilisateur jusqu'à ce que sa sélection soit correcte.
Ensuite, suivant l'option demandée, soit nous ajoutons une nouvelle note soit nous en supprimons une ou alors nous les
supprimons toutes.
Enfin, nous passons à l'affichage avec pas mal de petits traitements spécifiques.
La méthode run() se termine lorsque l'utilisateur choisi l'option 0. Cette méthode retourne également la
valeur 0 qui peut servir pour clôturer le programme.
Mise en oeuvre du codage
Respectez l'ensemble de ces diagrammes. Il est judicieux de s'occuper en premier de la classe Notes. Une fois que vous
l'avez complètement contituée, vous vous préoccupez ensuite de la classe Gestion qui utilise fréquemment les compétences de
la classe Notes appel de ses différentes méthodes. Pour finir, vous complèterez la fonction principale main().
#include <iostream>
using namespace std;
#include "gestion.h"
int Gestion::run()
{
do {
menu();
choix = choisir(3);
switch (choix)
{
case 1:
cout << "Note à rajouter : ";
cin >> note;
notes.ajouter(note);
break;
case 2:
cout << "Note à supprimer : ";
cin >> note;
notes.supprimer(note);
break;
case 3:
notes.toutSupprimer();
break;
}
afficheResultats();
}
while (choix!=0);
return 0;
}
void Gestion::menu()
{
cout << "------------------------------" << endl;
cout << "Ajouter une note ............1" << endl;
cout << "Enlever une note ............2" << endl;
cout << "Supprimer toutes les notes ..3" << endl;
cout << "Quitter .....................0" << endl;
cout << "------------------------------" << endl;
cout << "Votre choix ? ";
}
unsigned Gestion::choisir(unsigned limite)
{
unsigned choix;
do {
cin >> choix;
if (choix>limite)
{
cout << "ATTENTION ! Votre choix n'est pas prévu, recommencez" << endl;
menu();
}
}
while (choix>limite);
return choix;
}
void Gestion::afficheResultats()
{
cout << "--------------------------" << endl;
cout << "Tableau de notes : ";
tableauNotes();
cout << endl;
cout << "Valeur moyenne : " << notes.moyenne() << endl;
cout << "Note la plus haute : " << notes.maxi() << endl;
cout << "Note la plus basse : " << notes.mini() << endl;
}
void Gestion::tableauNotes()
{
cout << '[';
for (unsigned i=0; i<notes.getNombre(); i++) cout << notes[i] << ' ';
cout << (notes.getNombre()>0 ? "\b]" : "vide]");
}
main.cpp
#include <iostream>
using namespace std;
#include "gestion.h"
int main()
{
cout << "Démarrage du système de gestion de notes..." << endl;
Gestion gestionNotes(10);
return gestionNotes.run();
}
Calcul d'une distance à partir d'une trajectoire
Pour ce premier petit projet, je vous invite à créer une classe Trajectoire qui permet d'évaluer la distance parcourue à
partir d'un ensemble de points correspondant au trajet effectué. Afin de faciliter le traitement, la distance entre deux points
sera toujours considérée comme une droite la trajectoire correspond alors à une suite de segments consécutifs. Pour
que le calcul ne soit pas trop éloigné de la réalité, il faut donner des points le plus fréquemment possible.
Fonctionnalités du programme - diagramme des cas d'utilisation
À partir du point origine dans un plan, vous allez rajouter les points intermédiaires du trajet. Au fur et à
mesure, la distance parcourue se calcule automatiquement. Il est possible de proposer une nouvelle trajectoire en cliquant sur le
bouton .
Diagramme des classes
Structure de l'IHM et diagramme des composants
Mise en oeuvre du codage
Prenez bien le temps d'analyser chacun de ces diagrammes et respectez scrupuleusement ce qui vous est proposé.
Vous allez reprendre l'idée du projet de gestion de notes précédent, mais cette fois-ci, vous allez le développer en mode fenêtré.
Dans ce nouveau projet, reprennez dans son intégralité la classe Notes. Par rapport à une étude antérieure avec un
traitement sous forme de fonctions, nous allons rajouter une combo-box qui permettra de connaître les notes déjà
introduites et de sélectionner la note à supprimer éventuellement.
Fonctionnalités du programme - diagramme des cas d'utilisation
Par rapport au diagramme précédent, vous remarquez la présence d'un nouveau cas d'utilisation Sélectionner une note
qui s'effectue à l'aide de la combo-box.
Diagramme des classes
Diagramme des composants et structure de l'IHM
Mise en oeuvre du codage
Prenez bien le temps d'analyser chacun de ces diagrammes et respectez scrupuleusement ce qui vous est proposé. Dans ce projet,
vous récupérez entièrement les deux fichiers correspondants à la description de la classe Notes.
Nous allons modifier le projet précédent afin que la classe Notes ne soit plus limitée par un nombre de notes spécifique,
en faisant en sorte que le conteneur s'auto adapte suivant le nombre de notes introduites, sans limitation aucune. Pour cela, nous
allons prendre la classe vector comme unique attribut de la classe Notes. L'objectif de ce projet consiste à revoir
entièrement cette classe en prenant en compte ce nouvel attribut sans changer le comportement global du système de gestion des
notes, et de garder ainsi les mêmes fonctionnalités que précédemment.
Diagramme des classes
Mise en oeuvre du codage
Réajustez cette classe Notes afin maintenant de prendre en compte l'attribut notes de type vector<double>.
Seule la méthode supprimer() est difficile à faire par rapport aux connaissances que vous avez vous la mettrez
au point ultérieurement avec votre professeur. Il est en effet nécessaire de faire une recherche de la note introduite à
l'aide d'un algorithme déjà préfabriqué dans la librairie standard. Il s'agit de la fonction find() à voir avec
votre professeur.
Nous allons maintenant nous intéresser au développement d'une application embarqué sur pcDuino afin de gérer
l'afficheur AM-03127-LED. Nous avons déjà largement travaillé avec ce système, mais les programmes réalisés jusqu'à présent
étaient sous forme structuré programmation fonctionnelle. L'objectif de ce TP est pour l'instant de proposer les
mêmes fonctionnalités que précédemment mais avec une programmation plus modulaire en utilisant les objets. Le but est donc de
mettre au point une nouvelle classe Afficheur qui s'occupe de la gestion de l'affichage de cet élément physique AM-03127-LED.
Diagramme des cas d'utilisation
Le programme à réaliser est extrêmement simple puisqu'il s'agit d'afficher un seul mot, sur une seule page de l'afficheur avec une
durée limité de 10 secondes. Lorsque le temps est écoulé l'afficheur ne doit plus rien afficher. Mis à part le temps écoulé, nous
avons déjà réaliser ce type de programme, mais cette fois-ci la conception est plus modulaire et respecte la modélisation objet.
Diagramme de déploiement
Le diagramme de déploiement nous permet de bien voir les différents systèmes mis en jeu. Vous devez mettre en oeuvre du cross-développement
pour créer votre programme qui sera automatiquement déployé sur le système embarqué pcDuino à l'aide des trois fichiers
nécessaires à l'élaboration du projet. La classe Afficheur sera développée dans les deux fichiers afficheur.h et afficheur.cpp.
Vous placerez les fonctionnalités attendues dans le fichier principal main.cpp.
Diagramme des classes
D'après ce diagramme vous remarquez que la classe Afficheur est composée de deux attributs. D'une part l'attribut connexion
qui nous précise si le système est bien en communication avec avec l'afficheur AM-03127-LED prise USB branchée.
D'autre part l'attribut usb, issu de la classe serialib, qui représente l'interface série par connexion USB,
avec ses trois méthodes utiles pour ce projet : l'ouverture du port de communication, sa fermeture et la possibilité d'envoyer des
messages textuels.
Diagramme de séquence
Mise en oeuvre du codage
Respectez l'ensemble de ces diagrammes. Il est judicieux de s'occuper en premier de la classe Afficheur. Une fois que vous l'avez complètement constituée, vous vous préoccupez
ensuite de la fonction principale main().
#include "afficheur.h"
#include #include "afficheur.h"
#include <iostream>
using namespace std;
int main()
{
string mot;
Afficheur lcd;
if (lcd.etat())
{
cout << "Afficheur connecté" << endl;
cout << "Tapez votre mot à afficher : ";
cin >> mot;
lcd.affichePage(mot);
cout << "Fin du programme dans 10s !" << endl;
cout << "L'afficheur va s'éteindre complètement..." << endl;
sleep(10); // attente de 10s
}
else cout << "Afficheur non connecté" << endl;
}
Modification du programme principal
Modifiez la fonction principale, dans le fichier main.cpp, de telle sorte que nous voyons l'écoulement du temps des 10
secondes d'attente, comme cela vous est montré dans la figure ci-dessous :
main.cpp
#include "afficheur.h"
#include #include "afficheur.h"
#include <iostream>
using namespace std;
int main()
{
string mot;
Afficheur lcd;
if (lcd.etat())
{
cout << "Afficheur connecté" << endl;
cout << "Tapez votre mot à afficher : ";
cin >> mot;
lcd.affichePage(mot);
cout << "Fin du programme dans 9s";
cout.flush();
for (int temps=8; temps>=0; temps--)
{
sleep(1); // attente de 1s
cout << "\b\b" << temps << 's';
cout.flush();
}
cout << endl;
}
else cout << "Afficheur non connecté" << endl;
}