bonjour tout le monde, je voudrais réaliser des classes, liveres et emprunteurs sous visual c++, est-ce que quelqu'un peut m'aider?
merci
bonjour tout le monde, je voudrais réaliser des classes, liveres et emprunteurs sous visual c++, est-ce que quelqu'un peut m'aider?
merci
Bonjour,
kelkin peut surement t'aider, il vient sur le forum tout les jours, mais il faut lui poser tes questions en Français et en détaillant les points qui te pose des problèmes.
Le pire c'est qu'il existe vraiment sur le forum
On peut t'aider, mais pas faire le travail à ta place.
Il faut que tu nous expliques quel est ton problème, sur quoi tu bloques, avec le code qui pose problème. Là, c'est beaucoup trop vague.
alors, j'ai deux classes (livre, et client), tout d'abord je voudrais savoir est-ce-que je dois ajouter des autres classes ou ça suffit??
salut je vien de terminer la classe livre de mon projet:,
j'ai un petit problème avec ( error C2065: 'nouvversion'*: identificateur non déclaré)
et voila l'en-tete
et voila Livre.cpp:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 class livre { private: char *nomlivre; char *auteur; int version; public: livre();//const par defaut livre(char *nouvnom , char *nouvauteur , int version); ~livre(void); char *obtenirnom(); char *obtenirauteur(); int obtenirversion(); //modification void modifiernom(char *nouvnom); void modifierauteur(char *nouvauteur); void modifierversion(int nouvversion); void modifier (char *nouvnom , char *nouvauteur, int nouvversion); //affichage void afficher() const ; };
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85 // pro.cpp*: définit le point d'entrée pour l'application console. // #include "stdafx.h" #include "stdafx.h" #include "livre.h" #include<iostream> #include<string.h> #include<conio.h> livre::livre() { nomlivre = new char('\0'); auteur = new char('\0'); version = 0; } livre::livre(char *nouvnom, char *nouvauteur, int version) { nomlivre = new char[strlen(nouvnom)+1]; strcpy(nomlivre, nouvnom); auteur = new char[strlen(nouvauteur)+1]; strcpy(auteur, nouvauteur); version = nouvversion ; } livre::~livre() { delete[] nomlivre; delete[] auteur; } char *livre::obtenirnom() { return nomlivre; } char *livre::obtenirauteur() { return auteur; } int livre::obtenirversion() { return version; } void livre::modifiernom(char *nouvnom) { delete[] nomlivre; nomlivre = new char[ strlen (nouvnom)+1]; strcpy (nomlivre, nouvnom); } void livre::modifierauteur(char *nouvauteur) { delete[] auteur; auteur= new char[ strlen (nouvauteur)+1]; strcpy (auteur, nouvauteur); } void livre::modifierversion( int nouvversion) { version = nouvversion; } void livre::modifier(char *nouvnom, char *nouvauteur, int nouvversion) { delete[] nomlivre; nomlivre = new char[ strlen (nouvnom)+1]; strcpy (nomlivre, nouvnom); delete[] auteur; auteur = new char [ strlen (nouvauteur)+1]; strcpy (auteur, nouvauteur); version = nouvversion; } void livre::afficher() const { std::cout<<"("<<nomlivre<<","<<auteur<<","<<version<<std::endl; } void main() { livre unlivre; unlivre.modifiernom(""); unlivre.modifierauteur(""); unlivre.modifierversion(0); unlivre.afficher(); getch(); }
Alors, plusieurs choses pour améliorer la qualité et sureté de ton code.
1/ Utilise (si tu as le choix) std::string au lieu de char* pour tes chaînes de caractères. Tu trouveras std::string dans l'entête <string> (pas <string.h>, qui est un entête du langage C). Ca se manipule très facilement. Il y a une page dédiée aux strings dans la FAQ : http://cpp.developpez.com/faq/cpp/?page=strings
2/ <conio.h> ne te servira à rien, et ce n'est pas un entête standard. Tu peux le lever.
3/ Je ne suis pas sûr que le fait qu'il existe un constructeur ne prenant aucun argument soit correct. En effet, est-ce que ç'a un sens de construire un livre qui n'a ni nom, ni auteur, ni version ? Disons qu'il n'aurait probablement pas de contenu non plus, donc personne ne le lirait
4/ Il va te falloir au moins une autre classe. Celle-ci pourra par exemple s'appeler bibliotheque, et elle maintiendra une collection de livres. Après, tu peux modéliser éventuellement les prêts de livres par une classe qui met en relation un client et un ou plusieurs livres, à toi de voir.
Pour terminer, je te conseille de garder sous la main la FAQ C++ pendant que tu fais cela, elle est pleine de sagesse et de très bon conseil, et elle t'apprendra une quantité assez impressionnante de bonnes pratiques.
Bon courage
Bonjour,
une simple relecture de ton code devrait te permettre de résoudre ce petit problème
Sinon, peux-tu utiliser les std::string. Ce serait sans doute préférable dans un code C++ à la place des tableaux de char et des chaînes de type C.
Si tu ne peux utiliser les string alors fais un petit tour côté FAQ sur les problèmes des pointeurs (problème de copie, RAII, exception safety, pointeur intelligents...).
Dans la même veine, à la place du getch() hérité du C, tu peux t'intéresser à une approche C++ avec les flux.
Enfin, ton main devrait retourner un entier :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 int main(){ // ... return 0; // ou tout autre entier, avec en général : // 0 pour OK // 1 pour erreur // 2 pour info }
salut, j'ai un soucis avec le visual c++ 2008, quand je débogue le programme on m'affiche les messages suivants
Merci d'avance de votre aide.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 'projet.exe'*: Chargé 'C:\WINDOWS\system32\ntdll.dll' 'projet.exe'*: Chargé 'C:\WINDOWS\system32\kernel32.dll' 'projet.exe'*: Chargé 'C:\WINDOWS\WinSxS\x86_Microsoft.VC90.DebugCRT_1fc8b3b9a1e18e3b_9.0.30729.1_x-ww_f863c71f\msvcr90d.dll' 'projet.exe'*: Chargé 'C:\WINDOWS\WinSxS\x86_Microsoft.VC90.DebugCRT_1fc8b3b9a1e18e3b_9.0.30729.1_x-ww_f863c71f\msvcp90d.dll' Le programme '[3152] projet.exe: Natif' s'est arrêté avec le code 0 (0x0).
s'est arrêté avec le code 0 => le programme s'est bien exécuté.
salut a tous voila je voudrais réaliser un menu principal pour ce projet, juste pour apprendre le c++, et je manque des conseils
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 // Declaration du nom des classes que l'on va utiliser par la suite class Bibliotheque; class Ouvrage; class Exemplaire; // Liste les trois valeurs possible pour un accept enum OUVRAGE_STATUS { FALSE = false, TRUE = true, NOT_KNOWN, };
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 class Filtre { public: virtual ~Filtre() {} virtual OUVRAGE_STATUS accept(Ouvrage* o) = 0; virtual bool accept(Exemplaire* e) = 0; };
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74 // Definition de la classe exemplaire class Exemplaire { public: // Constructeur de la classe Exemplaire : // Trois parametres // - dateAchat: la date d'achat de l'exemplaire par la bibliotheque // (nombre de seconde depuis le 1er janvier 1970) // - dateEdition: la date d'edition de l'exemplaire // (nombre de seconde depuis le 1er janvier 1970) // - ouvrage: un pointer (l'adresse) de l'objet ouvrage correspondant. Exemplaire(int dateAchat, int dateEdition, Ouvrage* ouvrage) // List d'initialisation des donnees membres : dateAchat_(dateAchat), dateEdition_(dateEdition), disponible_(dateAchat != 0 && dateEdition != 0), ouvrage_(ouvrage) { // Corps du constructeur (vide) } // Fonction permettant de savoir si l'exemplaire // est disponible dans la bibliotheque ou non // La fonction est qualifie par le mot clef const car elle ne modifie // pas l'etat interne de l'objet bool estDisponible() const { return disponible_; } // Retourne la date d'achat int getDateAchat() const { return dateAchat_; } // Retourne la date d'achat int getDateEdition() const { return dateEdition_; } // Permet d'obtenir une reference vers l'objet ouvrage correspondant. Ouvrage& getOuvrage() const { return *ouvrage_; } // Il n'est pas necessaire d'ecrire des methode permettant de modifier // la date d'achat, la date d'edition ou encore l'ouvrage. // Ces informations ne sont pas amenee a changer dans le temps. // Cette methode permet d'emprunter un exemplaire void emprunter() { if (dateAchat_ != 0 && dateEdition_ != 0) // Si l'exemplaire est emprunte, // alors il n'est plus disponible disponible_ = false; } // Cette methode permet de rendre un exemplaire a la bibliotheque void rendre() { if (dateAchat_ != 0 && dateEdition_ != 0) // Si on rend l'exemplaire alors ce dernier est a nouveau // disponible disponible_ = true; } private: // Donnees membres (attributs). // L'etat de l'objet est prive. Il ne peut etre modifie que par // les methodes emprunter() et rendre(). int dateAchat_; int dateEdition_; bool disponible_; Ouvrage* ouvrage_; }; // Fin de la definition de la classe exemplaire
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137 class Ouvrage { public: // Definition des valeurs possible pour format // static signifie ici que les donnees sont commune a l'ensemble des // instance de la classe. Il est conseille de toujours definir // la valeur des variable static hors de la definition de la classe. // En effet, il n'est pas possible d'initialiser tout type de donnees // directement dans la classe il est donc plus pratique de toujours // initialiser hors de la classe. // Si l'on veut utiliser la constante FORMAT_LIVRE on ecrira : // FORMAT_LIVRE si l'on est entrain de definir la classe ouvrage // Ouvrage::FORMAT_LIVRE si l'on est l'utilisateur de la classe // ouvrage. static const int FORMAT_LIVRE; static const int FORMAT_CD; static const int FORMAT_DVD; static const int FORMAT_PERIODIQUE; static const int FORMAT_CASSETTE; // Constructeur de la classe Ouvrage // Ici je n'utilise pas de liste d'initialisation // C'est une seconde facon d'ecrire les constructeur. // Il est neanmoins recommende d'utiliser la liste d'initialisation // partout ou c'est possible. // Lorsque que l'argument est un objet, il est recommande de toujours // utilise le passage de parametre par reference constante. // CF cours sur le cycle de vie et le constructeur par copie Ouvrage(const std::string& auteur, const std::string& titre, const std::string& genre, int format) { auteur_ = auteur; titre_ = titre; genre_ = genre; format_ = format; exemplaires_.push_back(new Exemplaire(0, 0, this)); } ~Ouvrage() { for(size_t i = 0 ; i < exemplaires_.size() ; ++i) delete exemplaires_[i]; } // Accesseurs // Afin d'eviter la copie de l'objet on retourne des references constante const std::string& getAuteur() const { return auteur_; } const std::string& getTitre() const { return titre_; } const std::string& getGenre() const { return genre_; } // Pour les types de bases ( // - char / short / int / long / // - float / double / // - pointer / bool ) // il n'est pas necessaire re retourner une reference constante. int getFormat() const { return format_; } // Retourne le nombre d'exemplaire de cet ouvrage int getNombreExemplaire() const { return exemplaires_.size(); } // Retourne l'exemplaire de rang rang. Exemplaire* getExemplaire(int rang) { return exemplaires_.at(rang); } // Permet d'obtenir un exemplaire disponible parmis tous les exemplaires Exemplaire* getDisponible() { for (unsigned int i = 0 ; i < exemplaires_.size() ; ++i) { // Ici on stocke des pointeurs vers des exemplaires. On doit // donc utiliser l'operateur -> pour appeler la methode // (fonction) estDisponible de la classe exemplaire. if (exemplaires_[i]->estDisponible()) return exemplaires_[i]; } } // Ajoute un nouvel exemplaire pour l'ouvrage courant. Exemplaire& creerExemplaire(int dateAchat, int dateEdition) { // Ici on utilise push_back pour ajouter a la fin du vecteur. // new permet de creer un objet alloue dynamiquement. // Tout objet alloue dynamiquement n'est pas detruit lorsque l'on // sort de la porte (bloc). L'objet va donc perdurer a la fin de // l'execution de la fonction. // Attention c'est a nous de gerer la memoire associe a cet objet. // Il est a la charge du programmeur de liberer cette memoire quand // l'objet n'est plus util. // CF cours sur la gestion des resources par le biais de // l'encapsulation. exemplaires_.push_back(new Exemplaire(dateAchat, dateEdition, this)); return *exemplaires_.back(); } void recherche(Filtre* f, std::vector<Exemplaire*>& resultat) { for(size_t i = 0 ; i < exemplaires_.size() ; ++i) { if (f->accept(exemplaires_[i])) { resultat.push_back(exemplaires_[i]); } } } // Il manque la fonction permettant de supprimer un exemplaire. // On traitera cela lors de la prochaine seance de TP. private: // Donnee membre privee. std::string auteur_; std::string titre_; std::string genre_; int format_; // Stocke l'ensemble des exemplaires d'un ouvrage std::vector<Exemplaire*> exemplaires_; }; // Fin de la definition de la class Ouvrage const int Ouvrage::FORMAT_LIVRE = 1; const int Ouvrage::FORMAT_CD = 2; const int Ouvrage::FORMAT_DVD = 3; const int Ouvrage::FORMAT_PERIODIQUE = 4; const int Ouvrage::FORMAT_CASSETTE = 5; // Definition de la classe bibliotheque.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84 class Bibliotheque { public: // Constructeur Bibliotheque(const std::string& nom, const std::string& adresse) : nom_(nom), adresse_(adresse) { // Le constructeur n'a plus rien a faire //nom_ = nom; //adresse_ = adresse; } ~Bibliotheque() { for(size_t i = 0 ; i < ouvrages_.size() ; ++i) delete ouvrages_[i]; } // Accesseur const std::string& getNom() const { return nom_; } const std::string& getAdresse() const { return adresse_; } // Retourne le nombre d'ouvrages references dans la bibliotheque int getNombreOuvrage() const { return ouvrages_.size(); } // Retourne le nombre d'exemplaires tout ouvrage confondus que possede // la bibliotheque int getNombreExemplaire() const { int total = 0; // A COMPLETER par vous. for(size_t i = 0 ; i < ouvrages_.size() ; ++i) { total += ouvrages_[i]->getNombreExemplaire(); } return total; } // Ajouter un nouvel ouvrage a la bibliotheque Ouvrage& ajouterOuvrage(const std::string& auteur, const std::string& titre, const std::string& genre, int format) { // (allocation memoire dynamique) ouvrages_.push_back(new Ouvrage(auteur, titre, genre, format)); return *ouvrages_.back(); } // Ce qu'il manque : // - Fonction permettant de parcourir la liste des ouvrages // C'est identique au parcours des exemplaires associe a un ouvrage // Fonction de recherche: resultat un ensemble d'exemplaire std::vector<Exemplaire*> recherche(Filtre* f) { std::vector<Exemplaire*> resultat; for(size_t i = 0 ; i < ouvrages_.size() ; ++i) { if (f->accept(ouvrages_[i])) { ouvrages_[i]->recherche(f, resultat); } } return resultat; } private: // Nom de la bibliotheque std::string nom_; // Adresse std::string adresse_; // Stocke l'ensemble des ouvrages d'une bibliotheque. std::vector<Ouvrage*> ouvrages_; }; // Fin de la definition de la classe bibliotheque // La classe Filtre Auteur permet de selectionner les auteurs tel que decrit // par la chaine de caractere auteur.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 class FiltreAuteur : public Filtre { public: // constructeur FiltreAuteur(const std::string& auteur) : auteur_(auteur) { } // Si le nom de l'auteur de l'ouvrage correspond a la chaine de caractere // auteur_ alors authoriser la recherche dans les exemplaires OUVRAGE_STATUS accept(Ouvrage* o) { if (o->getAuteur() == auteur_) return TRUE; return FALSE; } // Si l'ouvrage correspond alors tous les exemplaires egalement. bool accept(Exemplaire* e) { return true; } private: std::string auteur_; }; class FiltreDisponible : public Filtre { public: OUVRAGE_STATUS accept(Ouvrage* o) { return NOT_KNOWN; } bool accept(Exemplaire* e) { if (e->estDisponible()) return true; return false; } };
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 class FiltreOu : public Filtre { private: Filtre* f1; Filtre* f2; public: FiltreOu(Filtre* f1, Filtre* f2) { this->f1 = f1; this->f2 = f2; } // Mauvais perte de genericite //FiltreOu(std::string& au1, std::string& au2) //{ // f1 = new FiltreAuteur(au1); // f2 = new FiltreAuteur(au2); //} OUVRAGE_STATUS accept(Ouvrage* o) { OUVRAGE_STATUS tmp = f1->accept(o); if (tmp == TRUE) return TRUE; OUVRAGE_STATUS tmp2 = f2->accept(o); if (tmp2 == TRUE) return TRUE; if (tmp2 == NOT_KNOWN || tmp == NOT_KNOWN) return NOT_KNOWN; return FALSE; } bool accept(Exemplaire* e) { if (f1->accept(e)) return true; return f2->accept(e); } };et voila j'ai eu un programme principal pour le filtre
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 class FiltreNon : public Filtre { public: FiltreNon(Filtre* f) : f_(f) {} OUVRAGE_STATUS accept(Ouvrage* o) { tmp = f_->accept(o); if (tmp == TRUE) return FALSE; else if (tmp == FALSE) return TRUE; return tmp; } bool accept(Exemplaire* o) { if (tmp == NOT_KNOWN) return !f_->accept(o); return TRUE; } private: Filtre* f_; OUVRAGE_STATUS tmp; };
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89 // Programme de test / point d'entree de l'application int main() { Bibliotheque b("UVSQ", "Batiment Buffon, 45 avenue des etats unis, 78035 Versailles CEDEX"); Ouvrage &o = b.ajouterOuvrage("Claude Delannoy", "Programmer en langage C++", "Culture numerique", Ouvrage::FORMAT_LIVRE); o.creerExemplaire(1, 5); o.creerExemplaire(2, 6).emprunter(); Ouvrage &o1 = b.ajouterOuvrage( "Herb Sutter", "Exceptional C++", "Culture numerique", Ouvrage::FORMAT_LIVRE); o1.creerExemplaire(3, 7); o1.creerExemplaire(4, 8); // Ajouter des ouvrages et des exemplaires ici. Ouvrage &o2 = b.ajouterOuvrage( "Inconnu", "Le C++ pour les null", "Inutile", Ouvrage::FORMAT_LIVRE); std::cout << "Nombre exemplaires : " << b.getNombreExemplaire() << std::endl; FiltreDisponible filtre0; std::vector<Exemplaire*> resDisponible = b.recherche(&filtre0); std::cout << "Resultats du filtre disponible(" << resDisponible.size() << "): " << std::endl; for (size_t i = 0; i < resDisponible.size() ; ++i) { std::cout << i << ": " << resDisponible[i]->getOuvrage().getAuteur() << ", " << resDisponible[i]->getOuvrage().getTitre() << ", " << resDisponible[i]->getDateAchat()<< std::endl; } // Test filtre Non sur exemplaire FiltreNon nonDispo(&filtre0); std::vector<Exemplaire*> resNonDispo = b.recherche(&nonDispo); std::cout << "Resultats du filtre non disponible(" << resNonDispo.size() << "): " << std::endl; for (size_t i = 0 ; i < resNonDispo.size() ; ++i) { std::cout << i << ": " << resNonDispo[i]->getOuvrage().getAuteur() << ", " << resNonDispo[i]->getOuvrage().getTitre() << ", " << resNonDispo[i]->getDateAchat() << std::endl; } // Test filtre auteur FiltreAuteur filtre1("Claude Delannoy"); std::vector<Exemplaire*> resClaudeDelannoy = b.recherche(&filtre1); std::cout << "Resultats du filtre Claude Delannoy(" << resClaudeDelannoy.size() << "): " << std::endl; for (size_t i = 0 ; i < resClaudeDelannoy.size() ; ++i) { std::cout << i << ": " << resClaudeDelannoy[i]->getOuvrage().getAuteur() << ", " << resClaudeDelannoy[i]->getOuvrage().getTitre() << ", " << resClaudeDelannoy[i]->getDateAchat() << std::endl; } // Test filtre non sur ouvrage FiltreNon nonClaude(&filtre1); std::vector<Exemplaire*> resNonClaude = b.recherche(&nonClaude); std::cout << "Resultats du filtre Non Claude Delannoy(" << resNonClaude.size() << "): " << std::endl; for (size_t i = 0 ; i < resNonClaude.size() ; ++i) { std::cout << i << ": " << resNonClaude[i]->getOuvrage().getAuteur() << ", " << resNonClaude[i]->getOuvrage().getTitre() << ", " << resNonClaude[i]->getDateAchat() << std::endl; } // Test du Filtre ou sur ouvrage FiltreAuteur filtre2("Herb Sutter"); FiltreOu ou(&filtre1, &filtre2); std::vector<Exemplaire* > resOu = b.recherche(&ou); std::cout << "Nombre de resultat de la recherche: " << resOu.size() << std::endl; std::cout << "Resultats: " << std::endl; for(size_t i = 0 ; i < resOu.size() ; ++i) { std::cout << resOu[i]->getOuvrage().getAuteur() << std::endl; } std::cout << "Filtre: Disponible ou Non Disponible" << std::endl; FiltreOu tous(&filtre0, &nonDispo); std::vector<Exemplaire*> resOu2 = b.recherche(&tous); std::cout << "Resultats: " << resOu2.size() << std::endl; std::cout << "Nombre Exemplaires total: " << b.getNombreExemplaire() << std::endl; //return 0; getch(); }
Salut, et bienvenue sur le forum.
Je dois avouer qu'il y a déjà de l'idée et que tu partage plus ou moins bien les responsabilités (pour ce que j'ai lu de manière transversale du code )
Cependant,je voudrais attirer ton attention sur quelques points, qui, bien qu'ils ne répondent pas forcément à ta question sont de nature à t'apporter une aide précieuse :
au sujet des booléens
les booléens (true et false) sont définis ainis:c'est à dire que, si, typiquement true est typiquement représenté par 1, il s'applique également à toute valeur différente de 0
- false est représenté par une valeur fausse (typiquement 0)
- true est représenté toutes valeurs ne pouvant pas être considérée comme fausse
De plus, si je comprend que le statut puisse être valide ou non (vrai ou faux), j'avoue ne pas très bien comprendre l'utilité d'un statut "inconnu"...
Tout cela me fait m'interroger grandement sur l'utilité de l'énumération OUVRAGE_STATUS en générale et de sa dernière valeur en particulier
Les listes d'initialisation
Lorsque tu définis un constructeur, il est possible et conseillé d'utiliser les listes d'initialisations pour initialiser les différents membres de la classe.
En effet, si le compilateur ne supporte pas un concept que l'on appelle le NRVO, le fait de ne pas les utiliser va provoquer un comportement d'initialisation aux valeurs par défaut suivi d'une assignation de valeur, qui peut elle-même être le résultat d'une copie et d'un "swap" des membres, alors que le fait d'utiliser les liste d'initialisation permet d'appeler le constructeur adéquat (le constructeur par copie, ou le constructeur normal) et de rendre ce seul appel suffisant.
Si, pour des données de types primitives, cela ne représente pas vraiment d'avantages (mais ne représente en tout cas aucun inconvénient), pour des données personnalisées complexes (principalement toutes les données manipulant des collections d'autres objet), cela peut représenter un gain de temps et d'utilisation de la mémoire assez important
Pour utiliser la liste d'initialisation, il "suffit" de placer la parenthèse fermante de la liste d'arguments et l'accolade ouvrante du bloc d'instructions du constructeur le symbole deux points " : " suivi par l'appel explicite des constructeurs particuliers de chaque membre (de préférence dans l'ordre de leur déclaration), séparé par une virugule
Cela donne un code proche de
Au sujet de l'utilisation des pointeurs et de l'allocation dynamiqueDe manière générale, le langage nous donnes un maximum de possibilités de nous passer de l'utilisation de pointeurs en dehors des cas où l'on n'a pas d'autres choix...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 MaClass::MaClass(Type1 m1, Type2 m2, Type3 m3/*,...*/): membre_1(m1), membre_2(m2), membre_3(m3)/*,... */ { /* il n'y a plus qu'à faire les tests de cohérences éventuels */ }
Les collections d'objets, dont la classes vector que tu utilise, sont l'un de ces moyens.
Au final, la gestion dynamique de la mémoire ne se justifie plus que dans quelques cas bien particuliers:
et l'utilisation même des pointeurs se limite, outre les deux cas sus-cités, au cas où l'on veut disposer d'une référence à l'objet contenant dans l'objet contenu.
- Lorsque l'objet créé a une durée de vie différente de l'objet qui le crée (et principalement si l'objet créé doit "survivre" à l'objet qui l'a créé)
- Lorsque l'on souhaite utiliser le polymorphisme (créer un objet d'un type dérivé en le faisant passer pour un objet du type de base)
Ainsi, si l'utilisation d'un pointeur sur Ouvrage se justifie dans un exemplaire, on peut malgré tout estimer qu'un exemplaire n'a aucune raison à "survivre" à un ouvrage donné (comment pourrait on avoir un exemplaire d'un ouvrage ... inexistant )...
De plus, les conteneurs de la STL ne sont pas particulièrement adaptés lorsqu'il s'agit de contenir des pointeurs sur des objets dont la mémoire a été allouée dynamiquement, ne serait-ce que parce qu'il faut penser à libérer soi-même la mémoire allouée dynamiquement avant d'effacer l'élément (ou les éléments) du conteneur.
L'idéal dans ce cas est soit d'utiliser des pointeurs dits "intelligents" (tels que shared_ptr), soit d'utiliser l'un des conteneurs particuliers fournis par boost (et qui va faire me semble-t-il son apparition dans la nouvelle norme) et dédié à la gestion de pointeurs: Boost:ointer Container
Au sujet des commentaires
Soyons francs: le débats sur l'utilité des commentaires est loin d'être fini...
Mais s'il y a consensus sur quelque chose, c'est que, si commentaires il y a, ils doivent être cohérents et apporter certaines précisions que l'on ne trouve pas dans le code...
Je me doute qu'il s'agit d'un copier / coller malheureux, mais, d'un point de vue de la cohérence, on peut estimer que cet extrait code peut faire mieux:
De plus, on peut se demander, même si le commentaire était cohérent (Retourne la date d'édition), si un tel commentaire apporte vraiment une précision que l'on ne trouve pas dans le code...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 // Retourne la date d'achat int getDateEdition() const { return dateEdition_; }
Quelque part, le nom même de la fonction permet de savoir sans équivoque possible ce qu'elle est sensée faire
Bonjour,
C'est un code assez bien construit
Quelques commentaire en vrac :
Personnellement je n'aime pas les constantes maisons qui ressemble à TRUE/FALSE quelque soit la casse. Je préfère des valeurs plus explicites qui présentent moins de risque de conflit :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 enum OUVRAGE_STATUS { FALSE = false, TRUE = true, NOT_KNOWN, };
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 enum OUVRAGE_STATUS { NOT_AVAILABLE = false, AVAILABLE = true, NOT_KNOWN, };
On préfère utiliser le pattern NVI (non virtual interface) pour la définition des interfaces :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 class Filtre { public: virtual ~Filtre() {} virtual OUVRAGE_STATUS accept(Ouvrage* o) = 0; virtual bool accept(Exemplaire* e) = 0; };
Cette approche sépare les responsabilités : la méthode non virtuelle pour les utilisateurs de la classe, la méthode virtuelle pour les classes dérivées. C'est en général un gage de meilleure souplesse face aux évolutions et s'intègrent mieux avec une approche par contrat.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 class Filtre { public: virtual ~Filtre() {} OUVRAGE_STATUS accept(Ouvrage* o) { do_accept(o); } bool accept(Exemplaire* e) { do_accept(e); } private : virtual OUVRAGE_STATUS do_accept(Ouvrage* o) = 0; virtual bool do_accept(Exemplaire* e) = 0; }; // Puis : class FiltreAuteur : public Filtre { public: // constructeur // etc.. private : // Si le nom de l'auteur de l'ouvrage correspond a la chaine de caractere // auteur_ alors authoriser la recherche dans les exemplaires OUVRAGE_STATUS do_accept(Ouvrage* o) // etc.- Ouvrage a un membre vecteur de pointeurs de Exemplaire (idem Bibliotheque a un membre vecteur de pointeurs d'ouvrage). Je ne vois pas l'intérêt d'avoir un vecteur de pointeur. Un vecteur de valeur devrait suffire car tu n'en fais pas d'utilisation polymorphique (pas de classe dérivées d'Expemplaire ou Ouvrage) et ce ne sont pas des objets partagés.
Si tu souhaites maintenir un vecteur de pointeur, alors il te faut soit interdire la copie de ta classe soit penser à gérer correctement cette copie (fais une recherche sur pointeur intelligent dans le forum). En outre, il faudrait gérer la possibilité d'une levée d'exception.- Tu gagnerais à consulter les algos de la STL qui pourraient t'aider à réécrire quelques unes de tes fonctions. Par exemples :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 Exemplaire* getDisponible() { std::vector<Exemplaire*>::const_iterator it = std::find_if( exemplaires_.begin(), exemplaires_.end(), std::mem_fun(&Exemplaire::estDisponible) ); if(it!=exemplaires_.end()){ return *it; } return NULL; }
Partager