Programmation Orientée Objet en C++ : Héritage, Composition et Classes Génériques

Expérience 1 :

(Expérience de vérification, à pratiquer personnellement, non à inclure dans le document de blog.)

Expérience 2 :

Code :

  1 #include <iostream>
  2 #include <vector>
  3 #include <string>
  4 #include <algorithm>
  5 #include <numeric>
  6 #include <iomanip>
  7 
  8 using std::vector;
  9 using std::string;
 10 using std::cin;
 11 using std::cout;
 12 using std::endl;
 13 
 14 class ResultatProf : public vector<int> {
 15 public:
 16     ResultatProf(const string &nomCours, int taille);      
 17     void saisir();                             // Saisir les résultats
 18     void afficher() const;                      // Afficher les résultats
 19     void trier(bool croissant = false);        // Trier (par défaut décroissant)
 20     int minimum() const;                        // Retourner la note minimale
 21     int maximum() const;                        // Retourner la note maximale
 22     float moyenne() const;                      // Retourner la moyenne
 23     void informations();                        // Afficher les informations sur les résultats du cours 
 24 
 25 private:
 26     void calculer();     // Calculer les statistiques
 27 
 28 private:
 29     string nom_cours;    // Nom du cours
 30     int effectif;        // Nombre d'étudiants
 31     vector<int> effectifs_bornes = vector<int>(5, 0);      // Stocker le nombre d'étudiants par tranche de notes ([0, 60), [60, 70), [70, 80), [80, 90), [90, 100]
 32     vector<double> pourcentages = vector<double>(5, 0);    // Stocker les pourcentages par tranche de notes 
 33 };
 34 
 35 ResultatProf::ResultatProf(const string &nomCours, int taille): nom_cours{nomCours}, effectif{taille} {}   
 36 
 37 void ResultatProf::saisir() {
 38     int note;
 39 
 40     for(int i = 0; i < effectif; ++i) {
 41         cin >> note;
 42         this->push_back(note);
 43     } 
 44 }  
 45 
 46 void ResultatProf::afficher() const {
 47     for(auto ptr = this->begin(); ptr != this->end(); ++ptr)
 48         cout << *ptr << " ";
 49     cout << endl;
 50 } 
 51 
 52 void ResultatProf::trier(bool croissant) {
 53     if(croissant)
 54         std::sort(this->begin(), this->end());
 55     else
 56         std::sort(this->begin(), this->end(), std::greater<int>());
 57 }  
 58 
 59 int ResultatProf::minimum() const {
 60     return *std::min_element(this->begin(), this->end());
 61 }  
 62 
 63 int ResultatProf::maximum() const {
 64     return *std::max_element(this->begin(), this->end());
 65 }    
 66 
 67 float ResultatProf::moyenne() const {
 68     return std::accumulate(this->begin(), this->end(), 0) * 1.0 / effectif;
 69 }   
 70 
 71 void ResultatProf::calculer() {
 72     for(int note: *this) {
 73         if(note < 60)
 74             effectifs_bornes.at(0)++;
 75         else if(note >= 60 && note < 70)
 76             effectifs_bornes.at(1)++;
 77         else if(note >= 70 && note < 80)
 78             effectifs_bornes.at(2)++;
 79         else if(note >= 80 && note < 90)
 80             effectifs_bornes.at(3)++;
 81         else if(note >= 90)
 82             effectifs_bornes.at(4)++;
 83     }
 84 
 85     for(int i = 0; i < pourcentages.size(); ++i)
 86         pourcentages.at(i) = effectifs_bornes.at(i) * 1.0 / effectif;
 87 }
 88 
 89 void ResultatProf::informations()  {
 90     cout << "Nom du cours:\t" << nom_cours << endl;
 91     cout << "Résultats triés: \t";
 92     trier();  afficher();
 93     cout << "Note maximale:\t" << maximum() << endl;
 94     cout << "Note minimale:\t" << minimum() << endl;
 95     cout << "Moyenne:\t" << std::fixed << std::setprecision(2) << moyenne() << endl;
 96     
 97     calculer();  // Calculer le nombre d'étudiants et les pourcentages par tranche de notes
 98 
 99     vector<string> tmp{"[0, 60)  ", "[60, 70)", "[70, 80)","[80, 90)", "[90, 100]"};
100     for(int i = tmp.size()-1; i >= 0; --i)
101         cout << tmp[i] << "\t: " << effectifs_bornes[i] << " étudiants\t" 
102              << std::fixed << std::setprecision(2) << pourcentages[i]*100 << "%" << endl; 
103 } 

ResultatProf.hpp``` 1 #include "ResultatProf.hpp" 2 #include 3 4 void tester() { 5 int nb_etudiants; 6 cout << "Saisir le nombre d'étudiants: "; 7 cin >> nb_etudiants; 8 9 ResultatProf cours1("POO", nb_etudiants); 10 11 cout << "Saisir les notes: " << endl;; 12 cours1.saisir(); 13 cout << "Afficher les notes: " << endl; 14 cours1.afficher(); 15 16 cout << string(20, '') + "Informations sur les résultats du cours" + string(20, '') << endl; 17 cours1.informations(); 18 } 19 20 int main() { 21 tester(); 22 }


tache2.cppRésultats d'exécution :

Répondre aux questions

Question 1 : Dans la définition de la classe dérivée ResultatProf, où sont stockées les notes ? Les méthodes de la classe dérivée trier, minimum, maximum, moyenne et afficher doivent accéder aux notes, par quel intergiciel accèdent-elles à chaque note ? La méthode saisir utilise quel intergiciel pour stocker les données dans l'objet ?

Réponse : Les notes sont stockées dans l'héritage de la classe vector de base. Les méthodes de la classe dérivée accèdent aux notes par l'intermédiaire des interfaces fournies par la classe vector de base : comme la méthode trier utilise la fonction std::sort, qui accepte les itérateurs begin et end du vector comme paramètres. Les méthodes minimum et maximum utilisent les fonctions std::min_element et std::max_element, et la méthode moyenne utilise la fonction std::accumulate pour calculer la somme de toutes les notes, puis divise par le nombre de notes. La méthode afficher parcourt le vector pour afficher chaque note. La méthode saisir utilise la fonction membre push_back du vector pour stocker les données dans l'objet.

Question 2 : Quelle est la fonction du dénominateur dans la ligne 68 du code ? Si on supprime le code multiplié par 1.0, recompile et exécute, y a-t-il un impact sur les résultats ? Pourquoi multiplier par 1.0 ?

Réponse : La fonction est de convertir un entier en nombre à virgule flottante pour effectuer une division. Le résultat serait impacté, car lors du calcul de la moyenne, sans division en virgule flottante, le résultat serait un entier, ce qui entraînerait une perte de la partie décimale de la moyenne. La multiplication par 1.0 convertit le numérateur en nombre flottant, garantissant ainsi que le résultat est également un nombre flottant, conservant ainsi la partie décimale.

Question 3 : Du point de vue des scénarios d'application réelle, quels aspects de la classe ResultatProf, tant dans la conception que dans les détails d'implémentation, n'ont pas été pris en compte et nécessitent toujours des itérations et des améliorations ?

Réponse : Concernant la validation des entrées, l'implémentation actuelle ne valide pas les notes saisies, par exemple si elles sont comprises entre 0 et 100. En termes de fonctionnalités, on pourrait ajouter plus de fonctionnalités, comme la suppression ou la modification de notes. En ce qui concerne les erreurs et exceptions, par exemple, lors du calcul de la moyenne, si le vector est vide (c'est-à-dire qu'aucune note n'a été saisie), le calcul direct entraînerait une erreur de division par zéro, il est donc nécessaire d'ajouter une vérification du vector vide.

Expérience 3 :

*Code :*


1 #include 2 #include 3 #include 4 #include 5 #include 6 #include 7 8 using std::vector; 9 using std::string; 10 using std::cin; 11 using std::cout; 12 using std::endl; 13 14 class GestionResultats { 15 public: 16 GestionResultats(const string &nomCours, int taille);
17 void saisir(); // Saisir les résultats 18 void afficher() const; // Afficher les résultats 19 void trier(bool croissant = false); // Trier (par défaut décroissant) 20 int minimum() const; // Retourner la note minimale 21 int maximum() const; // Retourner la note maximale 22 float moyenne() const; // Retourner la moyenne 23 void informations(); // Afficher les informations sur les résultats du cours 24 25 private: 26 void calculer(); // Calculer les statistiques 27 28 private: 29 string nom_cours; // Nom du cours 30 int effectif; // Nombre d'étudiants 31 vector notes; // Notes du cours 32 vector effectifs_bornes = vector(5, 0); // Stocker le nombre d'étudiants par tranche de notes ([0, 60), [60, 70), [70, 80), [80, 90), [90, 100] 33 vector pourcentages = vector(5, 0); // Stocker les pourcentages par tranche de notes 34 }; 35 36 GestionResultats::GestionResultats(const string &nomCours, int taille): nom_cours{nomCours}, effectif{taille} {}
37 38 void GestionResultats::saisir() { 39 int note; 40 41 for(int i = 0; i < effectif; ++i) { 42 cin >> note; 43 notes.push_back(note); 44 } 45 }
46 47 void GestionResultats::afficher() const { 48 for(int note: notes) 49 cout << note << " "; 50 cout << endl; 51 } 52 53 void GestionResultats::trier(bool croissant) { 54 if(croissant) 55 std::sort(notes.begin(), notes.end()); 56 else 57 std::sort(notes.begin(), notes.end(), std::greater()); 58
59 }
60 61 int GestionResultats::minimum() const { 62 return *std::min_element(notes.begin(), notes.end()); 63 }
64 65 int GestionResultats::maximum() const { 66 return *std::max_element(notes.begin(), notes.end()); 67 }
68 69 float GestionResultats::moyenne() const { 70 return std::accumulate(notes.begin(), notes.end(), 0) * 1.0 / effectif; 71 }
72 73 void GestionResultats::calculer() { 74 for(int note: notes) { 75 if(note < 60) 76 effectifs_bornes.at(0)++; 77 else if(note >= 60 && note < 70) 78 effectifs_bornes.at(1)++; 79 else if(note >= 70 && note < 80) 80 effectifs_bornes.at(2)++; 81 else if(note >= 80 && note < 90) 82 effectifs_bornes.at(3)++; 83 else if(note >= 90) 84 effectifs_bornes.at(4)++; 85 } 86 87 for(int i = 0; i < pourcentages.size(); ++i) 88 pourcentages.at(i) = effectifs_bornes.at(i) *1.0 / effectif; 89 } 90 91 void GestionResultats::informations() { 92 cout << "Nom du cours:\t" << nom_cours << endl; 93 cout << "Résultats triés: \t"; 94 trier(); afficher(); 95 cout << "Note maximale:\t" << maximum() << endl; 96 cout << "Note minimale:\t" << minimum() << endl; 97 cout << "Moyenne:\t" << std::fixed << std::setprecision(2) << moyenne() << endl; 98
99 calculer(); // Calculer le nombre d'étudiants et les pourcentages par tranche de notes 100 101 vector tmp{"[0, 60) ", "[60, 70)", "[70, 80)","[80, 90)", "[90, 100]"}; 102 for(int i = tmp.size()-1; i >= 0; --i) 103 cout << tmp[i] << "\t: " << effectifs_bornes[i] << " étudiants\t" 104 << std::fixed << std::setprecision(2) << pourcentages[i]*100 << "%" << endl; 105 }


GestionResultats.hpp```
 1 #include "GestionResultats.hpp"
 2 #include <iomanip>
 3 
 4 void tester() {
 5     int nb_etudiants;
 6     cout << "Saisir le nombre d'étudiants: ";
 7     cin >> nb_etudiants;
 8 
 9     GestionResultats cours1("POO", nb_etudiants);
10 
11     cout << "Saisir les notes: " << endl;;
12     cours1.saisir();
13     cout << "Afficher les notes: " << endl;
14     cours1.afficher();
15 
16     cout << string(20, '*') + "Informations sur les résultats du cours"  + string(20, '*') << endl;
17     cours1.informations();
18 }
19 
20 int main() {
21     tester();
22 }

tache3.cppRésultats d'exécution :

Répondre aux questions.

Question 1 : Dans la classe composite GestionResultats, où sont stockées les notes ? Les méthodes de la classe composite trier, minimum, maximum, moyenne et afficher doivent accéder aux notes, par quel intergiciel accèdent-elles à chaque note ? Observer les différences dans les détails de l'écriture du code par rapport à l'expérience 2.

Réponse : Stockées dans la variable membre privée notes, qui est de type vector. Les méthodes de la classe composite accèdent aux notes en accédant directement à la variable notes. Par rapport à l'expérience 2, la différence principale réside dans la manière dont les notes sont stockées. Dans l'expérience 2, les notes étaient stockées dans un vector hérité de la classe de base, permettant ainsi d'utiliser directement les fonctions membres du vector pour accéder et manipuler les notes. Dans l'expérience 3, les notes sont stockées dans une variable membre vector distincte, nécessitant l'accès à cette variable pour manipuler les notes.

Question 2 : En comparant l'expérience 2 et l'expérience 3, la logique principale du code (code de test) n'a pas changé, l'interface de la classe GestionResultats n'a pas changé, ce qui a changé, c'est la conception et les détails d'implémentation interne de l'interface de la classe GestionResultats. Avez-vous de nouvelles compréhensions ou réalisations sur la programmation orientée objet ?

Réponse : On peut mieux comprendre les concepts d'héritage et de composition en programmation orientée objet. Dans l'expérience 2, GestionResultats était implémenté par héritage de vector, ce qui signifie qu'il utilisait directement les interfaces et l'implémentation de la classe de base. L'avantage est qu'on peut utiliser directement les fonctionnalités de la classe de base, mais l'inconvénient est un couplage plus élevé, l'implémentation de la classe de base pouvant affecter la classe dérivée. Dans l'expérience 3, GestionResultats était implémenté en composant une variable membre vector, gérant soi-même le stockage et la manipulation des notes. L'avantage de cette méthode est un couplage plus faible, mais l'inconvénient est qu'il faut implémenter toutes les fonctionnalités soi-même. Le choix entre les deux méthodes dépend du scénario d'application et des besoins spécifiques.

Expérience 4 :

Code 1 :

 1 #include <iostream>
 2 #include <string>
 3 #include <limits>
 4 
 5 using namespace std;
 6 
 7 void test1() {
 8     string s1, s2;
 9     cin >> s1 >> s2;  // cin: lire des chaînes depuis le flux d'entrée, s'arrête au premier blanc (espace/entrée/Tab)
10     cout << "s1: " << s1 << endl;
11     cout << "s2: " << s2 << endl;
12 }
13 
14 void test2() {
15     string s1, s2;
16     getline(cin, s1);  // getline(): extraire des chaînes depuis le flux d'entrée jusqu'au caractère de nouvelle ligne
17     getline(cin, s2);
18     cout << "s1: " << s1 << endl;
19     cout << "s2: " << s2 << endl;
20 }
21 
22 void test3() {
23     string s1, s2;
24     getline(cin, s1, ' '); // extraire des chaînes depuis le flux d'entrée jusqu'au délimiteur spécifié
25     getline(cin, s2);
26     cout << "s1: " << s1 << endl;
27     cout << "s2: " << s2 << endl;
28 }
29 
30 int main() {
31     cout << "Test 1: Utiliser l'objet de flux d'entrée standard cin pour saisir des chaînes" << endl;
32     test1();
33     cout << endl;
34 
35     cin.ignore(numeric_limits<streamsize>::max(), '\n');
36 
37     cout << "Test 2: Utiliser la fonction getline() pour saisir des chaînes" << endl;
38     test2();
39     cout << endl;
40 
41     cout << "Test 3: Utiliser la fonction getline() pour saisir des chaînes avec un délimiteur spécifié" << endl;
42     test3();
43 }

tache4_1.cppRésultats d'exécution :

Répondre aux questions

Question 1 : Supprimer la ligne 35 de tache4_1.cpp, recompiler et exécuter, fournir une capture d'écran du résultat d'exécution. Consulter la documentation, répondre à la question de quelle est l'utilité de la ligne 35 ici ?

Capture d'écran des résultats d'exécution :

Consultation de documentation : la ligne 35 sert à effacer le contenu restant dans le flux d'entrée cin, jusqu'au caractère de nouvelle ligne '\n'. Ceci est généralement nécessaire car après les opérations d'entrée précédentes utilisant cin >>, il reste un caractère de nouvelle ligne dans le flux d'entrée. Si ce caractère n'est pas effacé, il affectera les appels ultérieurs de la fonction getline(), car getline() s'arrêtera à la première occurrence du caractère de nouvelle ligne.

Code 2 :

 1 #include <iostream>
 2 #include <string>
 3 #include <vector>
 4 #include <limits>
 5 
 6 using namespace std;
 7 
 8 void afficher(const vector<string> &v) {
 9     for(auto &s: v)
10         cout << s << endl;
11 }
12 
13 void test() {
14     int n;
15     while(cout << "Saisir n: ", cin >> n) {
16         vector<string> v1;
17 
18         for(int i = 0; i < n; ++i) {
19             string s;
20             cin >> s;
21             v1.push_back(s);
22         }
23 
24         cout << "Afficher v1: " << endl;
25         afficher(v1); 
26         cout << endl;
27     }
28 }
29 
30 int main() {
31     cout << "Test: Utiliser cin pour saisir plusieurs chaînes" << endl;
32     test();
33 }

tache4_2.cppRésultats d'exécution :

Code 3 :

 1 #include <iostream>
 2 #include <string>
 3 #include <vector>
 4 #include <limits>
 5 
 6 using namespace std;
 7 
 8 void afficher(const vector<string> &v) {
 9     for(auto &s: v)
10         cout << s << endl;
11 }
12 
13 void test() {
14     int n;
15     while(cout << "Saisir n: ", cin >> n) {
16         cin.ignore(numeric_limits<streamsize>::max(), '\n');
17 
18         vector<string> v2;
19 
20         for(int i = 0; i < n; ++i) {
21             string s;
22             getline(cin, s);
23             v2.push_back(s);
24         }
25         cout << "Afficher v2: " << endl;
26         afficher(v2); 
27         cout << endl;
28     }
29 }
30 
31 int main() {
32     cout << "Test: Utiliser la fonction getline() pour saisir plusieurs chaînes" << endl;
33     test();
34 }

tache4_3.cppRésultats d'exécution :

Répondre aux questions :

Question 2 : Supprimer la ligne 16 de tache4_3.cpp, recompiler et exécuter, fournir le résultat d'exécution. Consulter la documentation, répondre à la question de quelle est l'utilité de la ligne 16 ici ?

Résultat d'exécution :

Consultation de documentation : la ligne 16, comme dans la question 1, sert à effacer le contenu restant dans le flux d'entrée cin, jusqu'au caractère de nouvelle ligne '\n'.

Expérience 5 :

Code :

 1 #ifndef GMR_HPP
 2 #define GMR_HPP
 3 
 4 // Définition de la classe template GestionRessourcesJeu
 5 template<typename T>
 6 class GestionRessourcesJeu {
 7 private:
 8     T ressource;  // Membre de données privée, stockant la valeur de la ressource
 9 
10 public:
11     // Constructeur avec paramètres, initialisant la quantité de ressource
12     GestionRessourcesJeu(T valeur_initiale) : ressource(valeur_initiale) {}
13 
14     // Obtenir la quantité actuelle de ressource
15     T obtenir() const {
16         return ressource;
17     }
18 
19     // Mettre à jour la quantité de ressource, augmentation ou diminution
20     void mettreAJour(T variation) {
21         if (variation < 0 && ressource + variation < 0) {
22             ressource = 0;  // Si la réduction est inférieure à 0, définir à 0
23         } else {
24             ressource += variation;
25         }
26     }
27 };
28 
29 #endif // GMR_HPP

gmr.hpp``` 1 #include "gmr.hpp" 2 #include 3 4 using std::cout; 5 using std::endl; 6 7 void test1() { 8 GestionRessourcesJeu PDV_manager(99.99); 9 cout << "Points de vie actuels: " << PDV_manager.obtenir() << endl; 10 PDV_manager.mettreAJour(9.99); 11 cout << "Augmentation de 9.99 points de vie, points de vie actuels: " << PDV_manager.obtenir() << endl; 12 PDV_manager.mettreAJour(-999.99); 13 cout <<"Réduction de 999.99 points de vie, points de vie actuels: " << PDV_manager.obtenir() << endl; 14 } 15 16 void test2() { 17 GestionRessourcesJeu Or_manager(100); 18 cout << "Quantité d'or actuelle: " << Or_manager.obtenir() << endl; 19 Or_manager.mettreAJour(50); 20 cout << "Ajout de 50 pièces d'or, quantité actuelle: " << Or_manager.obtenir() << endl; 21 Or_manager.mettreAJour(-99); 22 cout <<"Réduction de 99 pièces d'or, quantité actuelle: " << Or_manager.obtenir() << endl; 23 } 24 25 26 int main() { 27 cout << "Test 1: Instanciation de la classe template GestionRessourcesJeu avec le type float" << endl; 28 test1(); 29 cout << endl; 30 31 cout << "Test 2: Instanciation de la classe template GestionRessourcesJeu avec le type int" << endl; 32 test2(); 33 }


tache5.cppRésultats d'exécution :

Expérience 6 :

Code :


1 #include 2 #include 3 4 using namespace std; 5 class Participant{ 6 public: 7 8 Participant(const string& pseudonyme,const string& contact,const string& ville,int nb):pseudonyme(pseudonyme),contact(contact),ville(ville),nb(nb){} 9 10 void afficher() const{ 11 cout<<"Pseudonyme :"<<pseudonyme<<endl; 12 cout<<"Coordonnées :"<<contact<<endl; 13 cout<<"Ville :"<<ville<<endl; 14 cout<<"Nombre de participants :"<<nb<<endl; 15 } 16 17 private: 18 19 string pseudonyme;// Pseudonyme 20 string contact;// Coordonnées 21 string ville; // Ville 22 int nb;// Nombre de participants inscrits 23 };


participant.hpp```
 1 #include "participant.hpp"
 2 #include <iostream>
 3 #include <vector>
 4 #include<string>
 5 #include<limits>
 6 #include <iomanip>
 7 
 8 using namespace std;
 9    int main() {
10      const int capacite = 100;
11      vector<Participant> liste_participants;
12      string pseudonyme, contact, ville;
13      int nb_participants, capacite_actuelle=0;
14      char choix;
15      cout<<"Saisie des informations de réservation des participants:"<<endl; 
16      cout << "Pseudonyme" << setw(40) << "Coordonnées (email/téléphone)" << setw(20) << "Ville" << setw(20) << "Nombre de participants" << endl;
17 
18      while(cin>>pseudonyme>>contact>>ville>>nb_participants){
19          cin.ignore(numeric_limits<streamsize>::max(), '\n');
20          if(capacite_actuelle+nb_participants>capacite){
21              cout<<"Désolé, il ne reste que "<<(capacite-capacite_actuelle)<<" places."<<endl;
22              cout<<"1. Saisir u, pour mettre à jour les informations de réservation"<<endl;
23              cout<<"2. Saisir q, pour quitter la réservation"<<endl;
24              cout<<"Votre choix : ";
25              cin>>choix;
26              if(choix=='u'){
27                 cout<<"Veuillez saisir à nouveau les informations de réservation :"<<endl;
28                  cin>>pseudonyme>>contact>>ville>>nb_participants;
29                  cin.ignore(numeric_limits<streamsize>::max(), '\n');
30              }
31              else
32              continue;
33          }
34          if(capacite_actuelle + nb_participants <= capacite){
35              liste_participants.push_back(Participant(pseudonyme, contact, ville, nb_participants));
36              capacite_actuelle += nb_participants;
37          }
38 
39      }
40      cout << "À ce jour, il y a un total de " << capacite_actuelle << " participants inscrits. Informations des participants inscrits :\n";
41      std::cout << "------------------------\n";
42      for (const auto& participant : liste_participants) {
43          participant.afficher();
44          std::cout << "------------------------\n";
45     }
46      return 0;
47  }

tache6.cppRésultats d'exécution :

Expérience 7 :

Code :

 1 #ifndef _ _DATE_H_ _
 2 #define _ _DATE_H_ _ 
 3 
 4 class Date{
 5     private:
 6         int annee;
 7         int mois;
 8         int jour;
 9         int totalJours;
10     public:
11         Date(int annee,int mois,int jour);
12         int getAnnee() const{return annee;}
13         int getMois() const{return mois;}
14         int getJour() const{return jour;}
15         int getMaxJour() const;
16         bool estBissextile() const{
17             return annee%4==0&&annee%100!=0||annee%400==0;
18         }
19         void afficher() const;
20         int distance(const Date& date) const{
21             return totalJours-date.totalJours;
22         }
23 };
24 
25 #endif //_ _DATE_H_ _

date.h``` 1 #include"date.h" 2 #include 3 #include 4 using namespace std; 5 namespace { 6 const int JOURS_AVANT_MOIS[] = { 0,31,59,90,120,151,181,212,243,273,304,334,365 }; 7 } 8 Date::Date(int annee, int mois, int jour) :annee{ annee }, mois{ mois }, jour{ jour } { 9 if (jour <= 0 || jour > getMaxJour()) { 10 cout << "Date invalide:"; 11 afficher(); 12 cout << endl; 13 exit(1); 14 } 15 int annees = annee - 1; 16 totalJours = annees * 365 + annees / 4 - annees / 100 + annees / 400 + JOURS_AVANT_MOIS[mois - 1] + jour; 17 if (estBissextile() && mois > 2)totalJours++; 18 } 19 int Date::getMaxJour()const { 20 if (estBissextile() && mois == 2) 21 return 29; 22 else return JOURS_AVANT_MOIS[mois] - JOURS_AVANT_MOIS[mois - 1]; 23 } 24 25 void Date::afficher()const { 26 cout << getAnnee() << "-" << getMois() << "-" << getJour(); 27 } 28 29 date.cpp


date.cpp```
 1 #pragma once
 2 #ifndef  ACCUMULATEUR_H
 3 #define  ACCUMULATEUR_H
 4 #include"date.h"
 5 class Accumulateur {
 6 private:
 7     Date derniereDate;
 8     double valeur;
 9     double somme;
10 public:
11     Accumulateur(const Date& date, double valeur) :derniereDate(date), valeur(valeur), somme{ 0 } {
12     }
13 
14     double getSomme(const Date& date)const {
15         return somme + valeur * date.distance(derniereDate);
16     }
17 
18     void changer(const Date& date, double valeur) {
19         somme = getSomme(date);
20         derniereDate = date; this->valeur = valeur;
21     }
22 
23     void reinitialiser(const Date& date, double valeur) {
24         derniereDate = date; this->valeur = valeur; somme = 0;
25     }
26 };
27 #endif//ACCUMULATEUR_H

accumulateur.h``` 1 #pragma once 2 #ifndef COMPTE_H 3 #define COMPTE_H 4 #include"date.h" 5 #include"accumulateur.h" 6 #include 7 class Compte { 8 private: 9 std::string id; 10 double solde; 11 static double total; 12 protected: 13 Compte(const Date& date, const std::string& id); 14 void enregistrer(const Date& date, double montant, const std::string& desc); 15 void erreur(const std::string& msg)const; 16 public: 17 const std::string& getId()const { return id; } 18 double getSolde()const { return solde; } 19 static double getTotal() { return total; } 20 21 void afficher()const; 22 }; 23 class CompteEpargne :public Compte { 24 private: 25 Accumulateur acc; 26 double taux; 27 public: 28 CompteEpargne(const Date& date, const std::string& id, double taux); 29 double getTaux()const { return taux; } 30 31 void deposer(const Date& date, double montant, const std::string& desc); 32 void retirer(const Date& date, double montant, const std::string& desc); 33 void cloturer(const Date& date); 34 }; 35 class CompteCredit :public Compte { 36 private: 37 Accumulateur acc; 38 double credit; 39 double taux; 40 double frais; 41 double getDebt()const { 42 double solde = getSolde(); 43 return (solde < 0 ? solde : 0); 44 } 45 public: 46 CompteCredit(const Date& date, const std::string& id, double credit, double taux, double frais); 47 double getCredit()const { return credit; } 48 double getTaux()const { return taux; } 49 double getCreditDisponible()const { 50 if (getSolde() < 0) 51 return credit + getSolde(); 52 else 53 return credit; 54 } 55 void deposer(const Date& date, double montant, const std::string& desc); 56 void retirer(const Date& date, double montant, const std::string& desc); 57 void cloturer(const Date& date); 58 void afficher()const; 59 }; 60 #endif//COMPTE_H


compte.h```
 1 #include"compte.h"
 2 #include<cmath>
 3 #include<iostream>
 4 using namespace std;
 5 double Compte::total = 0;
 6 
 7 Compte::Compte(const Date& date, const string& id) :id{ id }, solde{ 0 } {
 8     date.afficher(); cout << "\t#" << id << " créé" << endl;
 9 }
10 
11 
12 void Compte::enregistrer(const Date& date, double montant, const string& desc) {
13     montant = floor(montant * 100 + 0.5) / 100;
14     solde += montant;
15     total += montant;
16     date.afficher();
17     cout << "\t#" << id << "\t" << montant << "\t" << solde << "\t" << desc << endl;
18 }
19 
20 void Compte::afficher()const { cout << id << "\tSolde:" << solde; }
21 void Compte::erreur(const string& msg)const {
22     cout << "Erreur(#" << id << "):" << msg << endl;
23 }
24 
25 CompteEpargne::CompteEpargne(const Date& date, const string& id, double taux) :Compte(date, id), taux(taux), acc(date, 0) {}
26 
27 void CompteEpargne::deposer(const Date& date, double montant, const string& desc) {
28     enregistrer(date, montant, desc);
29     acc.changer(date, getSolde());
30 }
31 
32 void CompteEpargne::retirer(const Date& date, double montant, const string& desc) {
33     if (montant > getSolde()) {
34         erreur("fonds insuffisants");
35     }
36     else {
37         enregistrer(date, -montant, desc);
38         acc.changer(date, getSolde());
39     }
40 }
41 
42 void CompteEpargne::cloturer(const Date& date) {
43     double interet = acc.getSomme(date) * taux / date.distance(Date(date.getAnnee() - 1, 1, 1));
44     if (interet != 0)enregistrer(date, interet, "intérêts");
45     acc.reinitialiser(date, getSolde());
46 }
47 
48 CompteCredit::CompteCredit(const Date& date, const string& id, double credit, double taux, double frais) :Compte(date, id), credit(credit), taux(taux), frais(frais), acc(date, 0) {}
49 
50 void CompteCredit::deposer(const Date& date, double montant, const string& desc) {
51     enregistrer(date, montant, desc);
52     acc.changer(date, getDebt());
53 }
54 
55 void CompteCredit::retirer(const Date& date, double montant, const string& desc) {
56     if (montant - getSolde() > credit) {
57         erreur("crédit insuffisant");
58     }
59     else {
60         enregistrer(date, -montant, desc);
61         acc.changer(date, getDebt());
62     }
63 }
64 
65 void CompteCredit::cloturer(const Date& date) {
66     double interet = acc.getSomme(date) * taux;
67     if (interet != 0)enregistrer(date, interet, "intérêts");
68     if (date.getMois() == 1)
69         enregistrer(date, -frais, "frais annuel");
70     acc.reinitialiser(date, getDebt());
71 }
72 
73 void CompteCredit::afficher()const {
74     Compte::afficher();
75     cout << "\tCrédit disponible:" << getCreditDisponible();
76 }

compte.cpp``` 1 #include"compte.h" 2 #include 3 4 using namespace std; 5 6 int main() { 7 Date date(2008, 11, 1); 8 CompteEpargne ce1(date, "S3755217", 0.015); 9 CompteEpargne ce2(date, "02342342", 0.015); 10 CompteCredit cc(date, "C5392394", 10000, 0.0005, 50); 11 12 ce1.deposer(Date(2008, 11, 5), 5000, "salaire"); 13 cc.retirer(Date(2008, 11, 15), 2000, "achat d'un téléphone"); 14 ce2.deposer(Date(2008, 11, 25), 10000, "vente d'actions 0323"); 15 16 cc.cloturer(Date(2008, 12, 1)); 17 18 cc.deposer(Date(2008, 12, 1), 2016, "remboursement du crédit"); 19 ce1.deposer(Date(2008, 12, 5), 5500, "salaire"); 20 21 ce1.cloturer(Date(2009, 1, 1)); 22 ce2.cloturer(Date(2009, 1, 1)); 23 cc.cloturer(Date(2009, 1, 1)); 24 25 cout << endl; 26 ce1.afficher(); cout << endl; 27 ce2.afficher(); cout << endl; 28 cc.afficher(); cout << endl; 29 cout << "Total:" << Compte::getTotal() << endl; 30 return 0; 31 }


7_10.cppRésultats d'exécution :

Résumé :

Dans l'exemple intégré du chapitre 6, les différents comptes étaient placés dans un tableau, mais dans ce chapitre, ils sont traités comme des objets indépendants pour prouver qu'ils sont des instances de classes différentes et qu'ils ne peuvent pas être stockés avec un type de sortie uniforme.
Insuffisance : les deux classes dérivées CompteEpargne et CompteCredit. Bien qu'elles aient les mêmes fonctions membres deposer, retirer et cloturer, leurs implémentations étant différentes, elles ne peuvent être fournies que dans leurs classes respectives, étant donc des fonctions indépendantes les unes des autres.

Étiquettes: C++ Programmation orientée objet Héritage composition classes génériques

Publié le 19 juin à 06h41