Conception de Programmes - IUT de Paris - 1ère année – Cours 8 – Les entrées/sorties Comment fonctionnent les opérateurs > pour les types élémentaires ? –Principes –Détection des erreurs et réaction –Formatage des sorties Comment développer des opérateurs d’entrée/sortie pour ses propres types de données ?
Conception de Programmes - IUT de Paris - 1ère année – E/S de types de base Les opérateurs > sont définis pour tous les types de base –bool, int, float, char, char*, etc.. Ils sont définis dans Les variables cin et cout, cerr et clog désignent les flux standards (initialisés par le système) Exemple d’utilisation #include using namespace std; void main() { int i = 0; cin >> i; // lecture cout << i; // écriture }
Conception de Programmes - IUT de Paris - 1ère année – Les entrées d’entiers Prototype istream& operator<<(istream&, int&); Invocation cin >> i; // operator<<(cin, i); Principe –Si la 1ère opérande (le flux) est dans un état correct Saute les séparateurs (espace, tabulation et fin de ligne) Si le 1er caractère est numérique –Lit tous les caractères numériques consécutifs –Réalise une conversion et affecte la 2ème opérande (l’entier) –En cas de dépassement, la 1ère opérande (le flux) est positionnée en erreur Sinon –Remet dans le flux le caractère lu –Positionne la 1ère opérande (le flux) dans un état incorrect –Renvoie la 1ère opérande
Conception de Programmes - IUT de Paris - 1ère année – Conséquences –Les entrées peuvent être enchaînées –Si une lecture échoue, les suivantes échoueront L’état d’un flux peut être testé if (cin.fail()) // ou if (!cin) // réagir à l’erreur Plusieurs cas d’erreur sont possibles et peuvent être détectée –Le flux est corrompu ( cin.bad() ) –Fin de fichier atteinte ( cin.eof() ) –Les données ne sont pas au bon format ou il y eu un dépassement de capacité cin >> i >> j; cin
Conception de Programmes - IUT de Paris - 1ère année – Exemple de réaction à une erreur #include using namespace std; // lit un entier à partir de is et le stocke dans i // attend une nouvelle saisie en cas de faute de frappe // renvoie false en cas d’erreur non récupérable bool lectInt(istream& is, int& i) { is >> i; while (!is) { if (is.bad() || is.eof()) // erreur non récupérable return false; // erreur de saisie // effacer l'état d'erreur is.clear(); // ignorer tout jusqu'à \n is.ignore( INT_MAX,'\n'); // donner une nouvelle chance is >> i; } return true; }
Conception de Programmes - IUT de Paris - 1ère année – Les entrées pour les autres types Les séparateurs précédents les données sont toujours ignorés Les réels peuvent être saisis dans le format scientifique (31416.e-04 est une entrée valide) Les chaînes de caractères –Une chaîne lue ne contient aucun séparateur –Attention : Des dépassements de buffer peuvent avoir lieu char s[2]; cin >> s; // si l’utilisateur entre plus de 1 caractère // la zone mémoire suivant s est écrasée –Solution: Utiliser le type string (solution conseillée) string s; cin >> s; // la longueur de la chaîne est ajustée aux données saisies Utiliser la méthode getline (lecture d’une chaîne avec séparateur) char s[SIZE]; cin.getline(s, SIZE-1,’\n’); // lit jusqu’au prochain ‘\n’ ou SIZE-1 caractères
Conception de Programmes - IUT de Paris - 1ère année – Les sorties Les seules erreurs possibles sont non récupérables Le formatage des sorties est réalisé par le biais de manipulateurs Exemple cout << left; // positionne l’option alignement à gauche Les différents manipulateurs de formatage –setw(8)// largeur (sortie suivante) –left, right, internal// alignement –setfill('&')// car. de remplissage –fixed, scientific// format des réels –setprecision(2)// nombre de décimales –showpoint, showpos, showbase // format des nombres –setbase(16)// base (2, 8 ou 16) –boolalpha// booléen en rep. symb. –flush// vider le flux –...
Conception de Programmes - IUT de Paris - 1ère année – Exemple d’utilisation de manipulateurs #include #include // nécessaire pour les manipulateurs à paramètre using namespace std; void main() { double val[] = { , , 0.}; // sauvegarde de la configuration actuelle ios::fmtflags old = cout.flags(); cout << setprecision(2); cout << showpos; cout << internal << setfill(‘.'); cout << fixed; for (int i=0; i<3; i++) { cout << setw(10) << val[i] << endl; } // restauration de la configuration initiale cout << setiosflags(old); }
Conception de Programmes - IUT de Paris - 1ère année – Surcharge des opérateurs > Comme les autres, les opérateurs > peuvent être surchargés pour des classes définies par l’utilisateur Cela facilite grandement l’usage de vos classes –Pas de nécessité d’introduire de nouveau identificateur (ecriture, affiche, print, lecture, saisie, read, …) –Possibilité d’enchaîner les affichages (et les saisies) cout << "la date courante est le " << d << endl; Les opérateurs > doivent être surchargés par des fonctions (et non pas des méthodes) Pour une classe nommée Complexe, les prototypes seront ostream& operator<<(ostream& os, const Complexe& c); istream& operator<<(istream& is, Complexe& c);
Conception de Programmes - IUT de Paris - 1ère année – Exemple – complexe.hpp #ifndef _COMPLEXE_HPP_ #define _COMPLEXE_HPP_ #include // nécessaire car employé dans le.hpp using namespace std; class Complexe { public: Complexe(float r=0., float i=0.); // constructeur float reel() const;// 1er accesseur float imag() const;// 2ème accesseur Complexe operator+(const Complexe& c) const; private: float re, im; // partie réelle et imaginaire }; // opérateurs d’entrée et de sortie istream& operator>>(istream& is, Complexe& c); ostream& operator<<(ostream& os, const Complexe& c); #endif
Conception de Programmes - IUT de Paris - 1ère année – complexe.cpp #include "complexe.hpp" Complexe::Complexe(float r, float i) { re = r; im = i; } float Complexe::reel() const { return re; } float Complexe::imag() const { return im; } Complexe Complexe::operator+(const Complexe& c) const { return Complexe(re+c.re, im+c.im); }
Conception de Programmes - IUT de Paris - 1ère année – complexe.cpp (suite) ostream& operator<<(ostream& os, const Complexe& c) { os << '(' << c.reel() << ',' << c.imag() << ')'; return os; } istream& operator>>(istream& is, Complexe& c) { float r, i; is >> r >> i; if (is) // c n’est modifié que si pas d’erreur c = Complexe(r, i); return is; }
Conception de Programmes - IUT de Paris - 1ère année – main.cpp #include using namespace std; #include "complexe.hpp" void main() { Complexe c1(1., 2.), c2(2., 1.), c3; cout << c1 + c2 << endl; cout << "entrez un nombre complexe :"; cin >> c3; if (cin) cout << "vous avez saisi " << c3; else cout << "erreur de saisie"; cout << endl; }
Conception de Programmes - IUT de Paris - 1ère année – Conseils Les données saisies ne doivent être modifiées qu’en cas d’absence d’erreur Les erreurs doivent être détectées mais la seule réaction devrait être de positionner le flux en erreur (pas de lecture robuste dans l’opérateur >>) Un flux is de type istream peut être positionné en erreur par un appel à is.clear(ios_base::failbit) Le format des données accepté en entrée devrait être le même que le format de sortie
Conception de Programmes - IUT de Paris - 1ère année – Nouvelle implémentation de >> pour les complexes istream& operator>>(istream& is, Complexe& c) { float r, i; char x, y, z; x = y = z = 0; // nécessaire is >> x >> r >> y >> i >> z; if ( x!='(' || y!=',' || z!=')' ) is.clear(ios_base::failbit); if (is) c = Complexe(r, i); return is; }