Correction examen c++ [RÉSOLU]

Correction examen c++ [RÉSOLU] - C++ - Programmation

Marsh Posté le 26-02-2015 à 12:20:30    

Bonjour,  
Je vous contacte car j'ai un examen en C++ (à l'écrit) vendredi. J'ai une annale à laquelle j'ai répondu et je souhaiterais savoir si vous pourriez jeter un coup d'oeil aux réponses que j'ai apporté.  
Je vous joins l'annale et mes réponses:  
http://static.ccm2.net/codes-sources.commentcamarche.net/faq/images/CtGaifBm2cGpnO0UliYdwlGfIKDPIUXHzQso1hlFe2Nzml0Enm4vqWuR7zC6tiyc-exam2014-1-copie-s-.png?new
http://static.ccm2.net/codes-sources.commentcamarche.net/faq/images/EJfz4IMgcmyZk6Pgdfa7WdoDNbIYJtRXnMW1l5rAhD8KVVw7JnCxJ1BaJtTKiHgj-exam2014-2-copie-s-.png?new
 
Et voici mon code:
Client.h
 

Code :
  1. #ifndef __annale2014__client__
  2. #define __annale2014__client__
  3. //#include "agenceLocale.h"
  4. #include <iostream>
  5. #include <string>
  6. using namespace std;
  7. class Client {
  8. string nom;
  9. string adresse;
  10. AgenceLocale& agenceLocale;
  11. public:
  12.   Client(string n, string a, AgenceLocale& al);
  13.   AgenceLocale operator();
  14.   void afficher();
  15. };
  16. #endif /* defined(__annale2014__client__) */


 
Client.cpp
 

Code :
  1. #include "client.h"
  2. Client(string n="",string a="", AgenceLocale& al):this->nom(n), this->adresse(a), this->agenceLocale(al){}
  3. AgenceLocale operator() {return this->agenceLocale->nom;}
  4. void afficher() {cout << this->nom << this->adresse << this->*agenceLocale;}


 
Employe.h
 

Code :
  1. #ifndef __annale2014__employe__
  2. #define __annale2014__employe__
  3. #include "agenceLocale.h"
  4. #include <iostream>
  5. #include <string>
  6. using namespace std;
  7. class Employe {
  8. string nom;
  9. int id;
  10. AgenceLocale *agl;
  11. public:
  12.   Employe(string ="", int i = 0);
  13.   virtual void afficher();
  14.   virtual float calculerSalaire() = 0;
  15. };
  16. #endif /* defined(__annale2014__employe__) */


 
Employe.cpp
 

Code :
  1. #include "employe.h"
  2. Employe(string ="", int i = 0):this->nom(n), this->id(i) {this->agl = new AgenceLocale();}
  3. virtual void afficher() {cout << this->nom << this->id << this->*agl;}
  4. virtual float calculerSalaire() = 0;


 
Commercial.h
 

Code :
  1. #ifndef __annale2014__commercial__
  2. #define __annale2014__commercial__
  3. #include <iostream>
  4. #include <string>
  5. using namespace std;
  6. class Commercial:public Employe {
  7. float pourcentage;
  8. float fixe;
  9. public:
  10.   Commercial(string n="", int i =0, float p=0.0, float f=0.0);
  11.   public float calculerSalaire();
  12. }
  13. #endif /* defined(__annale2014__commercial__) */


 
Commercial.cpp
 

Code :
  1. #include "commercial.h"
  2. Commercial(string n="", int i =0, float p=0.0, float f=0.0):Employer(n,i), pourcentage(p), fixe(f) {}
  3. public float calculerSalaire(){}


 
AgenceLocale.h
 

Code :
  1. #ifndef __annale2014__agenceLocale__
  2. #define __annale2014__agenceLocale__
  3. #include "region.h"
  4. #include "employe.h"
  5. #include "client.h"
  6. #include "vente.h"
  7. #include <iostream>
  8. #include <string>
  9. #include <list>
  10. using namespace std;
  11. class AgenceLocale {
  12. string nom;
  13. Region& nomR;
  14. int nbEmp;
  15. Employe employe[nbEmp];
  16. list<Client> c;
  17. list<Vente> v;
  18. public:
  19.   AgenceLocale(string n, Region& r, int nb);
  20.   AgenceLocale(const AgenceLocale& copie);
  21.   void addEmploye(string nom, int id);
  22.   Vente AgenceLocale::operator[](int i);
  23.   ostream& operator<<(ostream& out, Client& c);
  24.   float calculerSalaire();
  25.   float salaireCommerciaux();
  26. };
  27. #endif /* defined(__annale2014__agenceLocale__) */


 
AgenceLocale.cpp
 

Code :
  1. #include "agenceLocale.h"
  2. AgenceLocale(string n="", Region& r, int nb = 0):this->nom(n), this->nomR(r), this->nbEmp(nb) {
  3.     employe = new Employe();
  4.     c = *new list<Client>();
  5.     v = *new list<Vente>();
  6. }
  7. AgenceLocale(const AgenceLocale& copie) {
  8.     this->nom = copie.nom;
  9.     this->nomR = copie.nomR;
  10.     this->nbEmp = copie.nbEmp;
  11.     this->employe = copie.employe;
  12.     this->employe = new Employe[copie.nbEmp];
  13.     for(int i = 0; i < nbEmp; i++) {
  14.         this->employe[i] = copie.employe[i];
  15.     }
  16.     c = copie.c;
  17.     v = copie.v;
  18. }
  19. void addEmploye(string nom, int id) {
  20.     Employe * e = new Employe(nom, id);
  21.     this->employe[nbEmp] = *e;
  22.     this->nbEmp++;
  23. }
  24. Vente AgenceLocale::operator[](int i) const {
  25.     return v[i];
  26. }
  27. ostream& operator<<(ostream& out, Client& c) {
  28.     for(list<Clien*> ::iterator it=lclient.begin(); it != lclient.endl();++it) {
  29.         out << it->c.nom << endl;
  30.     }
  31. }
  32. public float calculerSalaire() {
  33.     float somme = 0.0;
  34.     for(list<Employe*>::iterator it = lemploye.begin(); it != lemploye.end();++it) {
  35.         somme += it->calculerSalaire();
  36.     }
  37.     return somme;
  38. }
  39. public float salaireCommerciaux() {
  40.     float somme = 0.0;
  41.     for(list<Commercial*>::iterator it = lcommercial.begin(); it != lcommercial.end();++it) {
  42.         somme += it->calculerSalaire();
  43.     }
  44.     return somme;
  45. }


 
J'espère que vous pourrez m'indiquer où je me suis trompé et pourquoi.
Je vous remercie de votre aide!


Message édité par weezyf le 26-02-2015 à 16:36:09
Reply

Marsh Posté le 26-02-2015 à 12:20:30   

Reply

Marsh Posté le 26-02-2015 à 12:36:47    

Dans tout tes constructeurs, tu fais pas passer tes string en référence constante (ça compilera, mais les string seront copiées de partout c'est mal :D).
Dans client.cpp, tu mets la valeur par défault dans la définition, et pas la déclaration (string n = "" ça doit se faire dans le header)
Dans Employe, tu fais l'allocation de l'agence local dans le constructeur, donc techniquement ça veut dire que la lifetime de cette instance est géré strictement par "Employe".
De une c'est faux (à prioris c'est des employés dans une agence locale, non ?) et de plus tu ne désalloue jamais cette instance (et c'est globalement ce qui se passe pour tout tes new).

 

Dans AgenceLocale.cpp : Pourquoi tu fais une allocation dynamique pour c & v ? (qui d'ailleurs sont des noms absolument obscure et illisible...)
Ces variables là ne sont pas des pointeurs, ils sont construit en même temps que ton objet "AgenceLocale", là tu vient encore d'avoir un beau memory leak :D
Employe est censé être un tableau ?

 

Dans cette ligne : "employe = new Employe();" tu ne créé qu'un seul employé, pourquoi ?
Tu devrais plutôt faire employe = new Employe[nb].

 

La fonction addEmploye est fausse aussi.
Tu dois réallouer le tableau entier, mais dans ce cas utilise un std::vector<Employe>, ça simplifiera toute la vie entière. (ou std::vector<Employe*> si tu as besoin de polymorphisme)

 

Dans calculerSalaire / salairCommerciaux tu parcours des listes qui n'existent pas (lemploye et lcommercial).
Tu as aussi la surcharge de l'operateur [n] qui n'est pas définie dans le header de agencelocale.h, et dans ce cas renvoit aussi une référence constante :

 
Code :
  1. const Vente& AgenceLocale::operator[] ( int index ) const;
 

J'ai pas trop regardé le sujet ceci-dit, et très honnêtement j'ai pas vraiment le courage de le faire  :sweat:

 

Mais bon, en espérant avoir pu t'aider.

 

edit : Ah, aussi, private/public/protected c'est que dans le header, pas de public float XXX dans le cpp ça ne sert à rien.
Et fais gaffe à ta tabulation et surtout au nommage, là c'est carrément pas lisible..

 


Message édité par Terminapor le 26-02-2015 à 12:37:38

---------------
Perhaps you don't deserve to breathe
Reply

Marsh Posté le 26-02-2015 à 13:20:25    

Merci pour ta réponse ultra rapide!  :D  
 

Citation :

Dans tout tes constructeurs, tu fais pas passer tes string en référence constante (ça compilera, mais les string seront copiées de partout c'est mal :D).


 
Je ne comprends pas où je les fais passer en référence constantes, car les références constantes ne sont pas pour les constructeurs par copie?  
 

Citation :

Dans client.cpp, tu mets la valeur par défault dans la définition, et pas la déclaration (string n = "" ça doit se faire dans le header)


 
C'est noté merci  :)  
 

Citation :

Dans Employe, tu fais l'allocation de l'agence local dans le constructeur, donc techniquement ça veut dire que la lifetime de cette instance est géré strictement par "Employe".  
De une c'est faux (à prioris c'est des employés dans une agence locale, non ?) et de plus tu ne désalloue jamais cette instance (et c'est globalement ce qui se passe pour tout tes new).


 
Oui, c'est exact. Je n'avais pas vu ça comme ça. Du coup je supprime l'allocation du constructeur qui devient du coup:

Code :
  1. Employe(string nom="", int id = 0);
  2. Employe(string n, int i):this->nom(n), this->id(i) {}


 

Citation :

Dans AgenceLocale.cpp : Pourquoi tu fais une allocation dynamique pour c & v ? (qui d'ailleurs sont des noms absolument obscure et illisible...)
Ces variables là ne sont pas des pointeurs, ils sont construit en même temps que ton objet "AgenceLocale", là tu vient encore d'avoir un beau memory leak :D


 
A vrai dire, je ne sais pas vraiment pourquoi. En relisant mes cours et des exemples, j'ai vu que la déclaration était comme cela (désolé pour le nommage des variables, je suis tout à faire d'accord avec toi). "c" et "v" sont deux listes et je ne sais pas trop comment les déclarer dans le constructeur et le constructeur par copie...
 

Citation :

Employe est censé être un tableau ?


 
Dans AgenceLocale, "employe" est déclaré sous forme de tableau oui et il est censé en être un.
Après la classe Employe n'est pas un tableau.
 

Citation :

Dans cette ligne : "employe = new Employe();" tu ne créé qu'un seul employé, pourquoi ?
Tu devrais plutôt faire employe = new Employe[nb].


 
Si effectivement, tu as raison merci :)
 

Citation :

La fonction addEmploye est fausse aussi.
Tu dois réallouer le tableau entier, mais dans ce cas utilise un std::vector<Employe>, ça simplifiera toute la vie entière. (ou std::vector<Employe*> si tu as besoin de polymorphisme)


 
Je vois pas bien comment le construire...

Code :
  1. void addEmploye(string nom, int id) {
  2.     std::vector<Employe> e;
  3.     std::vector<Employe>::iterator it;
  4.    
  5.     it = e.begin();
  6.     it = e.insert(it, nom, id);
  7.     e.insert(it, nom, id);
  8.     this->employe[nbEmp] = *e;
  9.     this->nbEmp++;
  10. }


Totalement faux mais, presque?  :)  
 

Citation :

Dans calculerSalaire / salairCommerciaux tu parcours des listes qui n'existent pas (lemploye et lcommercial).


 
Oui oui, c'est vrai, j'ai oublié de les déclarer.
 

Code :
  1. list<Employe> lemploye;
  2. list<Commercial> lcommerciaux;


 

Citation :

Tu as aussi la surcharge de l'operateur [n] qui n'est pas définie dans le header de agencelocale.h, et dans ce cas renvoit aussi une référence constante :


 
J'ai pas trop compris là, dans mon header la surcharge de l'opérateur [] est bien définie non?
 

Citation :

Ah, aussi, private/public/protected c'est que dans le header, pas de public float XXX dans le cpp ça ne sert à rien.


 
Oups mégarde de ma part, merci !  :D  
 
Merci encore pour ta précieuse aide!


Message édité par weezyf le 26-02-2015 à 13:43:58
Reply

Marsh Posté le 26-02-2015 à 13:54:42    

Non, les références constante ça veut juste dire que c'est une référence vers une instance que tu ne modifiera pas.
Les références c'est exactement comme les pointeurs, sauf que tu n'a pas d'arithmétique dessus et que tu dois avoir l'objet sur lequel ca "pointe" lors de la création.
En gros, une référence c'est un pointeur qui est safe (enfin dans l'absolu ça peut partir en vrille, mais bon [:ddr555]).
 
Si tu as une méthode du genre :  
 

Code :
  1. class MaClass
  2. {
  3.     private:
  4.          std::string m_text;
  5.     public:
  6.          void foo();
  7. };
  8. void MaClass::foo( std::string text )
  9. {
  10.    m_text = text;
  11. }


 
L'appeler fera plusieurs copie de texte :  
 

Code :
  1. MaClass MC;
  2. std::string txt = "foobar";
  3. MC.foo(txt);


 
Tu feras copie txt -> argument de foo et argument de foo -> attribut m_text.
 
Le fait de faire passer par référence (ou pointeur, mais c'est moins safe et très "C" ) t'évitera la copie txt-> argument foo :  
 

Code :
  1. void foo( const std::string& text );


 
Pour l'histoire des new/delete, c'est lorsque tu as un pointeur :  
 

Code :
  1. std::list<type>* ma_liste = new std::list<type>(...);


 
Mais attention, ça veut dire que tu dois gérer la lifetime de ton instance (elle ne se supprimera pas toute seule).
Pour supprimer tu fais simplement

Code :
  1. delete ma_liste;


 
Si tu n'a pas de pointeur, tu n'a aucune raison de lancer des new et des deletes.
Et fais-en le moins possible, gérer la lifetime à la main est dangereux (des gens en sont mort :o)
 
Pour ce qui est du vector, il te le faut en attribut dans AgenceLocale :  
 

Code :
  1. class AgenceLocale
  2. {
  3.     private:
  4.         std::vector<Employe> TabEmploye;
  5. };


 
Et la fonction addEmploye donne ça :  
 

Code :
  1. void AgenceLocale::addEmploye( const std::string& nom, int id)
  2. {
  3.     TabEmploye.push_back(Employe(nom,id));
  4. }


 
Pour parcourir par iterateur, tu ferais comme ça :  
 

Code :
  1. for ( std::vector<Employe>::iterator it = TabEmploye.begin(); it != TabEmploye.end(); ++it)
  2. {
  3.     Employe& E = (*it);
  4.     // Ce que tu veux avec E
  5. }


 
Si tu as besoin de savoir combien de client il y a, tu peux utiliser la methode size().
 
Ceci-dit, pourquoi tu n'utilises que des std::list ?
std::vector est plus simple à manier, t'es pas obligé de parcourir par iterateur (tu peux faire un for (int i = 0 ; i < monvector.size(); ++i)), et est contigu (toutes tes instances sont les une à côté des autres, std::list est une liste chaînée, donc pointeur vers suivant/précédent pour chaque objet..)
 
Effectivement pour l'opérateur [] j'ai mal lu, excuse-moi :D
Par contre l'operateur() défini dans client est faux. Il est supposé renvoyer une agence locale mais là tu lui fait renvoyer un std::string.. Et il est censé signifier quoi ?
Ca te ferait une syntaxe comme ça :  
 

Code :
  1. Client C(...);
  2. AgenceLocale AL = C();


 
(bon je viens de lire, c'est dans le sujet et c'est honteux :o)
 
Cette surcharge est assez obscure, si tu veux récupérer l'agence locale d'un client fait plutôt une méthode qui s'appelle "getAgenceLocale" par exemple, au moins c'est clair.
 


---------------
Perhaps you don't deserve to breathe
Reply

Marsh Posté le 26-02-2015 à 14:32:20    

Citation :

Non, les références constante ça veut juste dire que c'est une référence vers une instance que tu ne modifiera pas.  
Les références c'est exactement comme les pointeurs, sauf que tu n'a pas d'arithmétique dessus et que tu dois avoir l'objet sur lequel ca "pointe" lors de la création.  
En gros, une référence c'est un pointeur qui est safe (enfin dans l'absolu ça peut partir en vrille, mais bon [:ddr555]).


 
Wokééééé je capte un peu mieux merci :)
 

Citation :

Mais attention, ça veut dire que tu dois gérer la lifetime de ton instance (elle ne se supprimera pas toute seule).


 
Effectivement, mais ce n'est pas l'instruction à placer dans le destructeur? Ou je dois le faire à chaque fois que je fais une instance?
 

Citation :

Et fais-en le moins possible, gérer la lifetime à la main est dangereux (des gens en sont mort :o)


 
Ahaha  :lol:  ok :)
 

Citation :

Et la fonction addEmploye donne ça


 
Ça marche, merci :)
 

Citation :

Ceci-dit, pourquoi tu n'utilises que des std::list ?


 
Car je dois suivre les instructions du sujet... Et les profs n'aiment pas trop les initiatives pour contourner leurs difficultés... -_-
Donc j'y suis contraint...
 

Citation :

Par contre l'operateur() défini dans client est faux. Il est supposé renvoyer une agence locale mais là tu lui fait renvoyer un std::string.. Et il est censé signifier quoi ?


 
C'est censé renvoyer un référence sur son agence locale.
Comme tu dis, il y a des choses dans le sujet qui sont pas toujours censées....
 

Citation :

Cette surcharge est assez obscure, si tu veux récupérer l'agence locale d'un client fait plutôt une méthode qui s'appelle "getAgenceLocale" par exemple, au moins c'est clair.


 
Je suis tout à fait d'accord avec toi, mais encore une fois, je sens que si je prends cette initiative les profs n'aiment pas car je contourne ce qu'ils demandent même si le résultat et le même....
De toute manière, faire un examen de langage sur du papier c'est pas vraiment censé non plus...
 
Juste pour pour quelques notions:
-quand j'ai un pointeur ou une liste dans une classe, comment ça se passe au niveau du constructeur et du constructeur par copie?
 
Merci encore pour ton aide, c'est vraiment génial !

Reply

Marsh Posté le 26-02-2015 à 15:36:12    

Pour ce qui est de la gestion de la lifetime, tu n'a pas spécialement de règle (rien qui entrave la compilation du moins)
Mais si tu fais l'allocation dans ton constructeur via un new, vaut mieux que ce soit cette classe qui fasse la désallocation dans le destructeur, mais tout dépend de ton modèle..
 
Pour ce qui est du constructeur de copie, std::list/std::vector ont leur opérateur de copie surchargé. Donc tu fais simplement ma_list = copie.ma_list et ça fera une copie.
Quand tu manipule un pointeur, ça dépend.
Si tu veux qu'ils partagent l'objet pointé, tu fais qu'une affection de pointeur (mais ça rend la gestion de la lifetime carrément obscure et pas trivial à gérer, à moins de passer par des smart pointers ou quoi).
Sinon tu peux simplement refaire une allocation dynamique :
 

Code :
  1. class C
  2. {
  3.    type* ptr;
  4.    public:
  5.        C ( const C& other )
  6.        {
  7.            ptr = new type((*other.ptr));
  8.        }
  9. };


---------------
Perhaps you don't deserve to breathe
Reply

Marsh Posté le 26-02-2015 à 15:40:43    

Citation :

Pour ce qui est du constructeur de copie, std::list/std::vector ont leur opérateur de copie surchargé. Donc tu fais simplement ma_list = copie.ma_list et ça fera une copie.  
Quand tu manipule un pointeur, ça dépend.  
Si tu veux qu'ils partagent l'objet pointé, tu fais qu'une affection de pointeur (mais ça rend la gestion de la lifetime carrément obscure et pas trivial à gérer, à moins de passer par des smart pointers ou quoi).  
Sinon tu peux simplement refaire une allocation dynamique :


 
Parfait j'y vois beaucoup plus clair maintenant!
Je te remercie énormément pour l'aide et les explications que tu m'as apporté, elles me sont très précieuses!  :D  
 
Je vais faire d'autres annales en prenant en compte tes explications, merci!!!
 
Edit: il n'y a pas de boutons résolu?


Message édité par weezyf le 26-02-2015 à 15:41:56
Reply

Marsh Posté le 26-02-2015 à 16:24:52    

Pas de soucis :)
 
Non y'a pas bouton résolu, tu peux éditer ton premier poste et changer le titre par contre.


---------------
Perhaps you don't deserve to breathe
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed