Traitement des données de compétition
Implémentation d'une structure Competiteur avec opérateurs spécialisés pour les opérations d'entrée/sortie :
#pragma once
#include <iomanip>
#include <string>
struct Competiteur {
long identifiant;
std::string prenom;
std::string filiere;
int problemes_resolus;
int penalite;
};
std::ostream& operator<<(std::ostream& flux, const Competiteur& c) {
flux << std::left
<< std::setw(12) << c.identifiant
<< std::setw(18) << c.prenom
<< std::setw(20) << c.filiere
<< std::setw(8) << c.problemes_resolus
<< std::setw(10) << c.penalite;
return flux;
}
std::istream& operator>>(std::istream& flux, Competiteur& c) {
return flux >> c.identifiant >> c.prenom >> c.filiere
>> c.problemes_resolus >> c.penalite;
}
La fonction enregistrer() démontre le polymoprhisme des flux grâce à la classe de base std::ostream :
void enregistrer(std::ostream& sortie, const std::vector<Competiteur>& liste) {
for (const auto& elem : liste) {
sortie << elem << '\n';
}
}
Cette conception permet d'utiliser indifféremment std::cout ou std::ofstream sans modification de code, exploitant l'héritage dans la hiérarchie des flux C++.
Amélioration de la résilience aux erreurs
La fonction de chargement suivante intègre une validation ligne par ligne pour gérer les données corrompues :
std::vector<Competiteur> charger(const std::string& chemin) {
std::ifstream entree(chemin);
if (!entree) throw std::runtime_error("Échec ouverture: " + chemin);
std::vector<Competiteur> resultat;
std::string ligne;
int numero_ligne = 0;
while (std::getline(entree, ligne)) {
numero_ligne++;
if (ligne.empty()) continue;
std::istringstream flux_ligne(ligne);
Competiteur participant;
if (flux_ligne >> participant) {
resultat.push_back(participant);
} else {
std::cerr << "[ERREUR L." << numero_ligne << "] Format invalide\n";
}
}
return resultat;
}
Cette approche évite les blocages dus aux données mal formatées, contrairement à l'implémentation originale qui ignorait les numéros de séquence et provoquait des erreurs silencieuses.
Système de gestion étudiante orienté objet
Classe Etudiant encapsulant les données avec méthodes d'accès sécurisées :
class Etudiant {
public:
std::string obtenir_filiere() const;
int obtenir_moyenne() const;
friend std::ostream& operator<<(std::ostream&, const Etudiant&);
friend std::istream& operator>>(std::istream&, Etudiant&);
private:
int matricule;
std::string nom;
std::string filiere;
int moyenne;
};
Le gestionnaire Gestionnaire implémente un tri multi-critères via expressions lambda :
void Gestionnaire::trier() {
std::sort(etudiants.begin(), etudiants.end(),
[](const Etudiant& a, const Etudiant& b) {
if (a.obtenir_filiere() != b.obtenir_filiere())
return a.obtenir_filiere() < b.obtenir_filiere();
return a.obtenir_moyenne() > b.obtenir_moyenne();
}
);
}
Cette structure permet une personnalisation flexible des critères de tri tout en respectant l'encapsulation des données.
Interface utilisateru interactive
Le menu principal gère les erreurs d'entrée avec nettoyage du flux :
void afficher_menu() {
std::cout << "\n--- Gestion Étudiants ---\n"
<< "1: Charger données\n"
<< "2: Trier\n"
<< "3: Afficher\n"
<< "4: Sauvegarder\n"
<< "5: Quitter\n";
}
void demarrer_application() {
Gestionnaire gestion;
int choix;
while (true) {
afficher_menu();
if (std::cin >> choix) {
// Traitement des choix
} else {
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "Erreur: Entrez un nombre\n";
}
}
}
La gestion des exceptions dans les opérations critiques garantit une sortie propre lors d'échecs d'E/S.