#include #include #include #include #include #include #include using namespace std; class Biere { string nom; string type; float deg_alcool; float prix; string region; public: void saisie(ifstream& stream); // Saisie (mais depuis le clavier) void saisie(); void affichage(); float get_deg_alcool() { return deg_alcool; } float get_prix() { return prix; } string get_nom() { return nom; } }; // Ici la fonction lecture n'est pas une template // car il doit ajouter au bon conteneur en fonction du type de bière // On aurait pu aussi imaginer une template, avec un "filtre", qui n'ajoute que // dans le conteneur passé en paramètre si le type == filtre. // Mais cela aurait nécessité 2lectures du fichier (ou une autre fonction) void lecture_fichier(list& belges, vector& etrangeres, const string fname) { ifstream file(fname); if (!file.is_open()) { cout << "Erreur lors de l'ouverture du fichier" << endl; return; } while (!file.eof()) { string type; Biere b; getline(file,type, ';'); b.saisie(file); if (type == "Belge") { belges.push_back(b); } else { etrangeres.push_back(b); } } } // La version template // En soit le 2e paramètre (T) n'est pas vraiment nécessaire parce que toujours = "Biere" // j'ai aucune idée de si il faut le mettre ou pas c'est un peu coup de poker avec // Benjelloun, il peut te dire fallait pas le mettre pour la raison que j'ai cité ci-dessus // mais aussi te dire mais il fallait le mettre (si on envisage l'inhéritance d'une classe bière) template void lecture_fichier_filtre(C& conteneur, const string type, const string fname) { ifstream file(fname); if (!file.is_open()) { cout << "Erreur lors de l'ouverture du fichier" << endl; return; } while (!file.eof()) { string t; getline(file, t, ';'); if (t != type) { file.ignore(200, '\n'); // passer la ligne, count=200 s'arrête dès que '\n'. continue; } T b; b.saisie(file); conteneur.push_back(b); } } template void affichage(C& c) { for (auto& a : c) { a.affichage(); } } string saisie_type_biere() { string t; cout << "Belge ou pas (O/N) :"; cin >> t; cin.ignore(); return t == "O" ? "Belge" : "Etranger"; } // Pareil ici pour le type T = "Biere" // j'aime beacoup la syntaxe // using T = typename C::value_type // qui évite de devoir passer T explicitement // mais pas sur que les assistants connaissent tous/ benjelloun apprécie template void ajout(C& conteneur) { T b; b.saisie(); conteneur.insert(conteneur.begin(), b); } void saisie_seuil(int& s) { cout << "Seuil : "; cin >> s; } template void erase_seuil_alcool(C& cont, float seuil) { // au lieu d'itérer on aurait aussi pu utiliser remove_if () // mais à lors il aurait fallut passer le "seuil" en paramètre avec l'équivalent // d'un "higher order function" ou d'un lambda // mais pas vu au cours donc on fait comme ça. auto it = cont.begin(); for (; it != cont.end(); /* il ne faut pas incrémenter l'itérateur à chaque fois, si on supprime on skip l'élement */) { // it-> est équivalent à une déréférence (*it) if (it->get_deg_alcool() >= seuil) { it = cont.erase(it); } else { it++; } } } // T= tjr bière en soit template bool comparer_prix(T& a, T& b) { return a.get_prix() < b.get_prix(); } template void plus_cher(C& cont) { // pour obtenir les bières LES + chers ont peu soit // itérer pour récupérer le max() en prix // puis réitéré et n'afficher que les bières ou // prix == max // ou sort le conteneur O(N logN) puis prendre les N premier // tant que N == prixPrecedent. // max_element marchera pas pour PLUSIEURS bières :( auto it = max_element(cont.begin(), cont.end(), comparer_prix); if (it == cont.end()) { cout << "Aucune bière dans le conteneur"; return; } // équivalent à (*it).get_prix(); float prixMax = it->get_prix(); for (auto& b : cont) { if (b.get_prix() == prixMax) { // b.affichage(); cout << b.get_nom() << " au prix de " << setprecision(4) << b.get_prix() << " euros" << endl; } } } int menu() { int choix; cout << "1. Stocker les bières Belge(s) dans une List et les bières Etrangere(s) dans un Vector + Afficher" << endl << "2. Ajouter au début une bière à List ou au Vector des bières selon si la bière est Belge ou pas" << endl << "3. Supprimer les bières dont le degré d'alcool est supérieure à un seuil donné par l’utilisateur" << endl << "4. Afficher les bières les plus chères du List et du Vector" << endl; cout << "Choix:" << endl; cin >> choix; return choix; } int main() { list belges; vector etrangeres; int seuil; setlocale(LC_ALL, ""); while (true) { switch (menu()) { case 1: // Ici, aucune idée de la bonne version // Aussi un coup de poker avec Benjelloun. // (lecture du fichier 2x vs pas de template+2conteneurs en paramètres) // Avec la première fonction lecture // lecture_fichier(belges, etrangeres, "Biere2.txt"); // Avec la seconde utilisant des templates et un filtre lecture_fichier_filtre, Biere>(belges, "Belge", "Biere2.txt"); lecture_fichier_filtre, Biere>(etrangeres, "Etrangere", "Biere2.txt"); cout << "Bières Belges:" << endl; affichage(belges); cout << "Bières étrangères" << endl; affichage(etrangeres); break; case 2: if (saisie_type_biere() == "Belge") { ajout, Biere>(belges); cout << "Bières Belges:" << endl; affichage(belges); } else { ajout, Biere>(etrangeres); cout << "Bières étrangères" << endl; affichage(etrangeres); } break; case 3: saisie_seuil(seuil); erase_seuil_alcool(belges, seuil); erase_seuil_alcool(etrangeres, seuil); cout << "Bières Belges:" << endl; affichage(belges); cout << "Bières étrangères" << endl; affichage(etrangeres); break; case 4: cout << "Les bières belges la plus chères sont" << endl; plus_cher(belges); cout << "Les bières étrangères la plus chères sont" << endl; plus_cher(etrangeres); break; default: return 0; // sortie } } } void Biere::saisie(ifstream& s) { string tmp; getline(s, nom, ';'); getline(s, type, ';'); getline(s, tmp, ';'); // POUR UNE RAISON QUE J'IGNORE complétement, sur VisualStudio 2022 // Avec windows en FRANCAIS, le stof lis les nombre avec des VIRGULES et pas des points // Il est nécessaire de retirer ceci en fonction de la plateforme ou du compilateur // Voir même de la langue de Windows (on pourra le faire mais je le fais pas) replace(tmp.begin(), tmp.end(), '.', ','); deg_alcool = stof(tmp); // fonction stof: String TO Float getline(s, tmp, ';'); // Pareil ici :/ replace(tmp.begin(), tmp.end(), '.', ','); prix = stof(tmp); getline(s, region, '\n'); } void Biere::affichage() { cout << nom << "; " << type << "; " << deg_alcool << "; " << prix<<"; "<> deg_alcool; cout << "Prix : "; cin >> prix; cin.ignore(); cout << "Région/Pays : "; getline(cin, region); }