Salut,
J'ai bien peur que je ne serai pas beaucoup plus agréable que mes prédécesseurs, mais il y a réellement beaucoup de place pour le progrès dans les deux fichiers de code que tu nous a fournis.
La règle de base, si tu veux programmer en C++, c'est de n'utiliser QUE le C++, et de ne te tourner vers des structures ou fonctions C que si tu ne peux vraiment pas faire autrement
Ainsi, les directive #define sont, autant que faire se peut, à éviter, et celle qui me chagrine le plus est sans nul doute
1 2
|
#define APP_PATH "D:\\Documents and Settings\\Administrateur\\Bureau\\Projet_Machine_Cafe\\Fichiers_Texte\\" |
En toute logique, la chaine de caractères qu'elle représente n'est nécessaire que dans la classe Distributeur, mais devra sans doute être commune à toutes les instances de Distributeur.
On peut donc estimer que cette chaîne de caractères est une bonne candidate pour devenir ce que l'on appelle un membre de classe (par opposition à un membre d'instance) de la classe Distributeur, et qu'elle peut être constante
Pour déclarer un membre de classe, le mot magique est "static" (cf Les entrées de la FAQ qui s'y rapportent), et cela prendrait sans doute la forme d'un
static const std::string app_path;
déclaré en privé dans la classe Distributeur et d'un
const std::string Distributeur::app_path="D:\\Documents and Settings\\Administrateur\\Bureau\\Projet_Machine_Cafe\\Fichiers_Texte\\"
dans Distributeur.cpp
De plus, il est important de penser à donner la préférence aux références (constantes si besoin) lorsque tu passe des paramètres, et, très souvent également lorsque tu renvoie un objet qui "survit" à l'appel de la fonction qui le renvoie...
Ainsi, le parametre string de tes méthode get_quelquechose et construire_quelquechose est un candidat idéal pour l'utilisation des référence constante (étant entendu que la chaine de caractères que tu passe en paramètre n'a a priori aucune raison d'être modifiée par la fonction qui la reçoit)
Ensuite, tu semble faire le distingo entre un "Lot_Piece", une "Boisson" et un "Ingredient", or, si j'ai bien compris, tu nous parle ici d'un distributeur automatique, et, à son niveau, on pourrait estimer que tout n'est que ElementDeStock, par exemple...
En effet, pour le Distributeur, il a n ingredients (qui se subdivisent sans doute ne n1 doses de cafe, n2 doses de chocolat, n3 dose de the, n4 doses de potage, n5 doses de supplément de lait, ...), m gobelets, o petites cuillères, et même p quantité d'eau (bien qu'il soit, vraisemblablement, relié à la distribution d'eau
), et, ce qu'il va faire c'est, à peu près dans l'ordre
- sortir un gobelet
- sortir une dose de café (ou de the, de chocolat ou de potage)
- sortir une dose de supplément de sucre (si demandé)
- sortir une dose de supplément de lait (si demandé)
- sortir une dose d'eau
- sortir une petite cuillère
et, pour lui, cela revient, tout simplement, à "sortir 6 fois un élément de son stock"
L'avantage de tout cela, c'est que tu pourras profiter à fond du polymorphisme, et en arriver à envisager un conteneur qui te permettra de retrouver plus rapidement l'élément de stock que tu veux...
En effet, le C++ fournit de base un tableau associatif: la map, disponible par inclusion du fichier d'en-tête <map> dans l'espace de nommage std, qui semble etre un candidat idéal pour maintenir au sein de ton Distributeur l'ensemble de ce qu'il contient, et dont la déclaration sous la forme (en tant que membre privé) de
1 2 3 4
| /* La chaine sert de clé pour la recherche, et n'est rien d'autre
* que le nom de tous les éléments de stock (cafe, the...)
*/
std::map<std::string,ElementDeStock*> stock; |
remplacera avantageusement les trois tab_quelquechose que tu a fournis.
En effet, il te suffira alors, pour la méthode, devenue unique, "getElementDeStock" de faire un
1 2 3 4 5 6 7 8 9 10 11 12
|
ElementDeStock* Distributeur::getElementDeStock(const std::string& name)
{
std::map<std::string, ElementDeStock*>::iterator it=stock.find(name);
/* c'est peut etre un élément qui n'est pas (ou plus) de stock ...
* dans ce cas, on renvoi NULL
*/
if(it=stock.end())
return NULL;
/* sinon, on renvoie l'élément sélectionné */
return (*it).second;
} |
(avis au puristes: je sais, les chaînes de caractères en tant que clé, c'est moyen moyen, mais ici, cela semble être la moins mauvaise solution
)
Il y a tellement à dire sur le code que tu présente que j'en viendrais presque à écrire tout un roman pour reprendre tous les points de conceptions qui sont à revoir, et donc, je vais me contenter de te donner le "coup de pousse" qui concerne la question initialement posée...
Comme indiqué au début du message, veille à n'utiliser en C++ QUE ce qui est C++...
Il faut donc éviter tout ce qui est fgets, strcpy, strcmp, FILE* et bien d'autre encore, car, pour la gestion de fichiers, le C++ fournit deux classes bien plus facile d'emploi: ifstream (fichiers en lecture) et ofstream (fichiers en écriture), toutes les deux accessibles par inclusion du fichier <fstream> dans l'espace de nommage std.
Tu trouvera un tas d'information sur l'utilisation de ces classes dans la section de la FAQ qui y est consacrée, mais en gros, pour lire ton fichier, tu pourrait te contenter (au fait, le ; n'est pas le meilleur séparateur que tu pouvais choisir: avec un ifstream, tu peux parfaitement laisser simplement un espace
) d'un
(c'est crade, mais cela pourra aller, avec des espace entre les données)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
std::string nomfich;
/* construction de la chaine nomfich */
std::string nom;/*le Nom */
int qa; /* la Qantite_Actuelle*/
int nbd; /*le Nb_Dose*/
int qm;/* laQuantite_Max */
std::ifstream ifs(nomfich.c_str())
if(ifs)
{
while(ifs>>nom)
{
ifs>>qa>>nbd>>qm;
/*"yapuka" créer l'objet... */
}
}
else
{
//le fichier n'est pas ouvert,y a peut etre quelque chose à faire ;)
} |
Pour ce qui est de l'écriture, il faut savoir qu'un fichier est quelque chose de "gravé dans le marbre"...
On peut éventuellement rajouter quelque chose à la fin (en l'ouvrant en mode "append"), mais, si tu veux modifier les données, il faut "casser la pierre", et tout recommencer à zéro...
Ici, il faudra donc réécrire à chaque fois le fichier en entier (ce qui pourrait te permettre de créer des fichiers "datés", ce qui ne serait peut etre pas plus mal, histoire d'avoir un "historique"
), et cela se ferait sous la forme de
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
std::string nomfich; /* le nom du fichier à utiliser */
/* construction du nom de fichier */
std::ofstream ofs(nomfich.c_str());
if(ofs)
{
/* on est parti sur une std::map<std::string, ElementDeStock*>
* nommee stock
*/
for(std::map<std::string, ElementDeStock*>::iterator it=stock.begin();
it!=stock.end();it++)
{
ofs<< (*it).first<<" "<
<<(*it).second->getRestant()<<" "
<<(*it).second->getQuantite()<<" "
<<(*it).second->getMax();
}
}
else
{
/* le fichier n'est pas ouvert, il y a peut etre quelque chose à faire ? */
} |
où, tu l'aura sans doute compris, getRestant(), getQuantite() et getMax() sont des comportements génériques qui peuvent s'appliquer à un élément de stock et qui fournissent respectivement la quantite actuelle, le nombre de doses et la quantité maximale
Partager