Rédaction personnalisée i / o

Certains programmeurs ne sont pas de grands fans de surcharger les opérateurs standards pour des classes C ++ définis par l'utilisateur. Cela comprend la rédaction d'insertion et extracteurs personnalisés. Cependant, de nombreux programmeurs préfèrent la création de leurs opérateurs d'entrée / sortie propre personnalisés. Cette introduction vous emmène à travers les étapes de création d'une première insertion personnalisé (de sortie), puis un extracteur personnalisé (d'entrée).

Sommaire

Créez la classe

Créer votre classe sans égard à l'entrée ou de sortie. Comprendre obtenir et ensemble fonctions pour extraire et de définir les valeurs individuelles dans un objet. L'exemple suivant est un Étudiant classe pour l'utilisation dans cette section. Voici le contenu de la Student.h fichier include:

Étudiant de classe {public: étudiants explicite (const char * pszName = "", à long id = 0, double GPA = 0.0) - // L'EEG et les fonctions prévues pour cette classstring getName () const-vide setName (string s) -Long getID () const-vide SETID (long nID) -double getGPA () const-vide setGPA (Double DGAP) -} -

Ce code ne comprend pas la mise en oeuvre de la obtenir et ensemble méthodes. Leurs détails ne devraient pas influencer la création de l'insertion et de l'extracteur.

L'hypothèse ci-dessus est que le ensemble fonctions effectuent un certain type de contrôles pour déceler les entrées invalides - par exemple, setGPA () ne devrait pas vous permettre de définir la moyenne cumulative pour une valeur en dehors de la plage 0,0 à 4,0.

Créer un dispositif d'insertion simples

L'insertion devrait afficher une Étudiant opposer soit pour l'affichage ou à un fichier. Le prototype suivant serait ajouté à la Student.h fichier include:

ostream operatorlt; lt; (ostream out, étudiant const s) -

L'insertion est déclarée avec un type de retour ostream et renvoie l'objet qui lui est passé. Sinon, une commande comme celle-ci ne serait pas travailler:

cout lt; lt; «Mon élève est" lt; lt; myStudent lt; lt; endl-

L'objet retourné par lt; lt; myStudent est utilisé dans la lt; lt; endl qui suit.

La mise en œuvre de cette insertion est simple (normalement elle apparaître dans la Student.cpp fichier):

ostream operatorlt; lt; (ostream out, étudiant const s) {int prev = out.precision (2) départ privé lt; lt; s.getName () lt; lt; "(" lt; lt; s.getID () lt; lt; ")" lt; lt; »/« lt; lt; s.getGPA () - retourner sortie}

Essayez-le et faire des ajustements

Donc, nous allons voir comment cela fonctionne insertion:

// CustomIO - développer un dispositif d'insertion et d'extraction personnalisé # include #comprendre #comprendre #include "student.h" using namespace std-int main (int argc, char * pargs []) {s1 Étudiant ("Davis", 123456, 3.5) -cout lt; lt; s1 lt; lt; endl-Student ("Eddins", 1, 3) -cout lt; lt; s2 lt; lt; endl-cout lt; lt; "Appuyez sur Entrée pour continuer ..." lt; lt; endl-cin.ignore (10, ' n') - cin.get () - retourner 0-}

Cela génère la sortie suivante:

Davis (123,456) /3.5Eddins (1) / 3

Si cela est correct, alors vous avez terminé. Cependant, pour les applications professionnelles, vous voudrez probablement mettre en œuvre quelques règles de sortie comme celle-ci (ce ne sont que des exemples):

  • # 42 Une école à laquelle la carte d'étudiant sont six chiffres. Si le nombre est inférieur à un complet de six chiffres, le nombre devrait être complétée à gauche avec des zéros.

  • Moyennes point n ° 42-Etat sont normalement affichés avec deux chiffres après la virgule.

Heureusement, il ya des contrôles qui implémentent ces fonctions. Cependant, être un peu prudent avant d'ajuster la mise en forme de sortie. Par exemple, supposons que l'insertion vous vouliez sortie un paramètre entier est au format hexadécimal. Les utilisateurs de l'insertion seraient très surpris si toute sortie ultérieure apparu en hexadécimal plutôt que décimal. Par conséquent, il est important d'enregistrer ce que les paramètres précédents sont et de les restaurer avant de revenir de notre insertion.

Une version de l'insertion gussied apparaît comme suit:

ostream operatorlt; lt; (ostream out, étudiant const s) {dehors lt; lt; s.getName () lt; lt; "(" - // Forcer id soit six chiffres fieldchar prevFill = out.fill ('0') - out.width (6) départ privé lt; lt; s.getID () - out.fill (prevFill) - // maintenant, sortie le reste de la Studentint prevPrec = out.precision (3) -ios_base :: fmtflags prev = out.setf (ios_base :: showpoint) départ privé lt; lt; ")" lt; lt; »/« lt; lt; s.getGPA () - out.precision (prevPrec) -out.setf (prev) -Retour sortie}

Vous pouvez voir que le dispositif d'insertion reproduit le nom de l'étudiant tout comme avant. Toutefois, avant la sortie de l'ID de l'étudiant, il définit la largeur de champ à six caractères et définit le caractère de remplissage gauche à 0.

La largeur du champ applique qu'à la sortie très prochaine de sorte qu'il est important de mettre immédiatement cette valeur avant que le champ que vous voulez avoir un impact. Parce qu'elle dure pendant un seul champ, il est inutile d'enregistrer et de restaurer la largeur de champ.

Une fois que le champ a été sortie, le caractère de remplissage est restauré à ce qu'il était avant. De même, la précision est définie à trois chiffres et la virgule est forcé avant d'afficher la moyenne cumulative. Cela force 3 à afficher comme 3,00.

Le résultat obtenu apparaît comme suit:

Davis (123456) /3.50Eddins (000001) /3.00

L'extracteur

Le travail de création de l'extracteur commence réellement avec l'insertion. Notez que dans la création du format de sortie pour mon SÉTUDIANT objet, le programmeur a ajouté certaines marques spéciales qui permettraient un extracteur pour faire en sorte que ce qu'il a lu est en fait un Étudiant. Par exemple, elle a inclus parenthèses autour de la carte d'étudiant et une barre oblique entre elle et l'AMP.

Mon extracteur peut lire ces champs pour vous assurer qu'il va rester en synchronisation avec le flux de données. En vue d'ensemble, l'extracteur devra accomplir les tâches suivantes:

  • # 42-Lire le nom (une chaîne de caractères).

  • # 42-Lire une parenthèse ouverte.

  • # 42-Lire un identifiant (un nombre entier).

  • # 42-Lire une parenthèse fermée.

  • # 42-Lire une barre oblique.


  • # 42 Lire l'AMP (un nombre à virgule flottante).

Il devra le faire tout tout le temps en étant conscient du fait que d'un problème de formatage se produit. Ce qui suit est ma version de l'extracteur de l'étudiant:

istream operator >> (istream dans, étudiant s) {// lire les valeurs (ignorer l'espace blanc supplémentaire) string nom long nID double DGAP-char openParen = 0, closedParen = 0, slash = 0-ios_base :: fmtflags prev = in.setf (ios_base :: skipws) -in nom >> >> >> openParen nID >> closedParen >> slash >> DGAP-in.setf (prev) - // si les marqueurs ne correspondent pas ... si (openParen = '(' || closedParen = ')' || slash = '/') {// ... alors ce ne est pas un Studentin.setstate juridique (ios_base :: failbit) -Retour à -}! // essayez de définir la valuestry étudiant {s.setName (nom) -s.setID (NID) -s.setGPA (DGAP) -} catch (...) {// quelque chose cloche - Signalez le failurein.setstate (ios_base :: failbit) -throw- } return in-}

Cette insertion commence par la lecture de chacun des domaines attendus comme précédemment décrit dans l'organigramme. Si l'un des caractères marqueurs est manquant (la parenthèse ouverte, fermée entre parenthèses, and slash), alors ceci est non juridique Étudiant objet. La manière correcte pour indiquer un tel échec est réglé le failbit dans l'objet d'entrée. Cela va arrêter tout entrée jusqu'à ce que la panne est effacé.

L'étape suivante consiste en fait à tenter de stocker ces valeurs dans le Étudiant. Par exemple, tous les marqueurs peut avoir été présente, mais la valeur lue pour la moyenne cumulative peut-être été de 8,0, une valeur qui est clairement hors de notre gamme prédéfinie de 0 à 4.0. En supposant que le Étudiant objet comprend la vérification des valeurs hors de portée dans ses méthodes set, l'appel à setGPA () lèvera une exception qui est pris dans l'extracteur. Encore une fois, l'extracteur définit la failbit. Que l'extracteur rethrows l'exception est au programmeur.

Il est beaucoup mieux de compter sur la setGPA () méthode pour détecter le problème de la portée que de mettre en œuvre un tel contrôle dans l'extracteur lui-même. Mieux vaut laisser le Étudiant objet de protéger son propre état que de compter sur des fonctions externes.

Utilisez ces nouvelles méthodes

Le (très) simple suivant CustomIO programme montre comment ces méthodes d'insertion et d'extraction sont utilisés. Cet exemple avec la coutume Étudiant d'insertion et d'extraction sont disponibles à Dummies.com:

int main (int argc, char * pargs []) {s1 Étudiant ("Davis", 123456, 3.5) -cout lt; lt; s1 lt; lt; endl-Student ("Eddins", 1, 3) -cout lt; lt; s2 lt; lt; endl-cout lt; lt; "Saisir un objet d'étudiant:" - cin >> s1-si (cin.fail ()) {cout lt; lt; "Erreur de lecture des élèves" lt; lt; endl-cin.clear () -} else {cout lt; lt; "Lire:" lt; lt; s1 lt; lt; endl-} cout lt; lt; "Appuyez sur Entrée pour continuer ..." lt; lt; endl-cin.ignore (10, ' n') - cin.get () - retourner 0-}

La sortie de ce programme (lorsqu'il est fourni un étudiant juridique en entrée apparaît comme suit:

Davis (123456) /3.50Eddins (000001) /3.00Input un objet d'étudiant: Laskowski (234567) /3.75Read: Laskowski (234567) /3.75Press Entrée pour continuer ...

Notez que l'étudiant Davis affiche tout comme nous voulions: l'identifiant de l'étudiant est entouré par des parenthèses et la moyenne cumulative apparaît avec deux chiffres après la virgule. Ce dernier est vrai même pour l'étudiant Eddins quelque peu problématique.

L'étudiant Laskowski est accepté comme entrée, car il dispose de toutes les marques propres d'un étudiant valide: parenthèses et slash dans tous les bons endroits. Découvrez ce qui se passe si nous laissons quelque chose sur, cependant:

Entrée un objet de l'étudiant: Laskowski 234567 / 3.75Error lecture étudiant

Ce petit programme montre deux habitudes très importantes que vous devez développer:

  • Vérifiez le drapeau échouent en appelant échec () après chaque entrée.

  • Désactivez le drapeau échouer dès que vous avez reconnu l'échec en appelant clear ().

    Toutes les demandes suivantes pour l'entrée seront ignorés jusqu'à ce que vous avez effacé le drapeau échouer.


» » » » Rédaction personnalisée i / o