Escritura e / s personalizada

Algunos programadores no son grandes fans de la sobrecarga de los operadores estándar para las clases definidas por el usuario en C ++. Esto incluye la escritura insertadores y extractores personalizados. Sin embargo, muchos programadores prefieren crear sus operadores de entrada / salida propia personalizados. Esta introducción se lleva a través de los pasos de crear primero un dispositivo de inserción personalizado (salida) y luego un extractor de encargo (de entrada).

Crear la clase

Cree su clase sin que respecta a la entrada o salida. Incluir obtener y conjunto funciones para recuperación y configuración de los valores individuales dentro de un objeto. El siguiente ejemplo es una Estudiante clase para su uso en esta sección. Estos son los contenidos de la Student.h archivo de inclusión:

Estudiante clase {public: Estudiante explícita (const char * = pszName ", Siempre id = 0, doble GPA = 0.0) - // el get y funciones establecidas para este classstring getName () const setName-vacío (cadena& s) -long getID () const-vacío SETID (larga NID) -doble getGPA () const setGPA de huecos (doble DGPA) -} -

Este código no incluye la aplicación de la obtener y conjunto métodos. Sus detalles no deben influir en la creación de la unidad de inserción y extracción.

La suposición anterior es que la conjunto funciones realizan algún tipo de control para detectar una entrada no válida - por ejemplo, setGPA () No debe permitir establecer el promedio de calificaciones a un valor fuera del rango de 0,0 a 4,0.

Crear un insertor sencilla

El insertor debe ser la salida de una Estudiante objetar ya sea para la exhibición o en un archivo. El siguiente prototipo se añadiría a la Student.h archivo de inclusión:

ostream& operatorlt; lt; (ostream& cabo, Estudiante const& s) -

El insertor se declara con un tipo de retorno de ostream& y devuelve el objeto que se le pasa. De lo contrario, un comando como el siguiente no funcionaría:

cout lt; lt; "Mi estudiante es " lt; lt; mi estudiante lt; lt; endl-

El objeto devuelto desde lt; lt; mi estudiante se utiliza en el lt; lt; endl que sigue.

La implementación de este dispositivo de inserción es sencillo (normalmente esto aparecería en el Student.cpp archivo):

ostream& operatorlt; lt; (ostream& cabo, Estudiante const& s) {int prev = out.precision (2) salida privado lt; lt; s.getName () lt; lt; " (" lt; lt; s.getID () lt; lt; ")"lt; lt; "/" lt; lt; s.getGPA () - devuelve OUT-}

Probarlo y hacer los ajustes

Así que vamos a ver cómo funciona este dispositivo de inserción:

// CustomIO - desarrollan un insertador de costumbre y extractores # include #incluir #incluir #incluir "student.h"using namespace std-int main (int argc, char * pargs []) {s1 Estudiante ("Davis", 123456, 3.5) -cout lt; lt; s1 lt; lt; endl-Estudiante s2 ("Eddins", 1, 3) -cout lt; lt; s2 lt; lt; endl-cout lt; lt; "Pulse Intro para continuar ..." lt; lt; endl-cin.ignore (10, `n`) - cin.get () - volver 0-}

Esto genera el siguiente resultado:

Davis (123456) /3.5Eddins (1) / 3

Si esto es correcto, entonces ya está. Sin embargo, para aplicaciones profesionales, es probable que desee poner en práctica algunas reglas salida como la siguiente (estos son sólo ejemplos):

Video: Crea tu propia fuente de texto o letra para ordenador

  • * Una escuela en la que los ID de los estudiantes son seis dígitos de longitud. Si el número es menor que un total de seis dígitos, entonces el número debe ser rellenada por la izquierda con ceros.

    Video: COMO MEJORAR TU LETRA Y TENER LETRA BONITA EN 10 MINUTOS

  • * promedio de calificaciones normalmente se muestran con dos dígitos después del punto decimal.

Afortunadamente, hay controles que implementan estas características. Sin embargo, ser un poco cuidadoso antes de ajustar el formato de salida. Por ejemplo, supongamos que el insertor que quería salida de un parámetro entero está en formato hexadecimal. Los usuarios de la unidad de inserción sería muy sorprendido si toda la producción posterior apareció en hexadecimal en lugar de decimal. Por lo tanto es importante registrar lo que los ajustes anteriores son y restaurarlos antes de volver de nuestra inserción.

Una de las versiones del dispositivo de inserción gussied aparece como sigue:

ostream& operatorlt; lt; (ostream& cabo, Estudiante const& s) {a cabo lt; lt; s.getName () lt; lt; " ("- // forzar el ID de ser una de seis dígitos fieldchar prevFill = out.fill ( `0`) - out.width (6) salida privado lt; lt; s.getID () - out.fill (prevFill) - // ahora de salida del resto de la Studentint prevPrec = out.precision (3) -ios_base :: fmtflags prev = out.setf (ios_base :: showpoint) salida privado lt; lt; ")" lt; lt; "/" lt; lt; s.getGPA () - out.precision (prevPrec) -out.setf (ant) -Retorno OUT-}

Se puede ver que el insertor da salida a nombre del estudiante al igual que antes. Sin embargo, antes de dar salida Identificación del estudiante, establece el ancho del campo a seis caracteres y define el carácter de relleno a la izquierda 0.

La anchura del campo se aplica solamente a la siguiente salida por lo que es importante establecer este valor inmediatamente antes del campo que desea impactar. Debido a que tiene una duración de sólo un campo, no es necesario registrar y restaurar el ancho del campo.

Una vez que el campo ha sido la producción, el carácter de relleno es restaurado a lo que era antes. Del mismo modo la precisión se establece en tres dígitos y el punto decimal se ve obligado a antes de mostrar el promedio de calificaciones. Esto obliga a un 3 a mostrar como 3.00.

La salida resultante aparece como sigue:

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

el extractor

El trabajo de crear el extractor en realidad comienza con la inserción. Nótese que en la creación del formato de salida para mi Student objeto, el programador añadió ciertas marcas especiales que permitan un extractor para asegurarse de que lo que está leyendo es en realidad una Estudiante. Por ejemplo, se incluyó paréntesis alrededor del carné de estudiante y una barra entre éste y el GPA.

Mi extractora puede leer estos campos para asegurarse de que se está quedando en sincronía con el flujo de datos. En general, el extractor necesitará para llevar a cabo las siguientes tareas:

  • * Leer el nombre (una cadena de caracteres).

  • * Leer un paréntesis abierto.

  • * Leer un ID (un número entero).

  • * Leer un paréntesis cerrado.

  • * Leer una barra.

  • * Lea el GPA (un número en coma flotante).

Tendrá que hacer esto, aunque es consciente de si se produce un problema de formato todo el tiempo. Lo que sigue es mi versión del extractor del estudiante:

istream& operatorgt; gt; (istream& en, Estudiante& s) {// leer los valores (ignorar el espacio en blanco adicional) cadena de nombre de longitud nID doble DGPA-char openParen = 0, closedParen = 0, slash = 0-ios_base :: fmtflags prev = in.setf (ios_base :: skipws) -en gt; gt; namegt; gt; openParen gt; gt; nID gt; gt; closedParengt; gt; barra oblicua gt; gt; DGPA-in.setf (ant) - // Si los marcadores no coinciden ... si (openParen = `(` || closedParen = `)` || slash = `/`!!!) {//. ..then esto no es un Studentin.setstate legal (ios_base :: failbit) -Retorno en -} // tratar de establecer el valuestry estudiante {s.setName (nombre) -s.setID (nID) -s.setGPA ( DGPA) -} catch (...) {// algo no está bien - Bandera del failurein.setstate (ios_base :: failbit) -throw-}} volver in-

Este dispositivo de inserción se inicia mediante la lectura de cada uno de los campos esperados como se describe anteriormente en el diagrama de flujo. Si cualquiera de los caracteres de marcador no se encuentra (el paréntesis de apertura, cierre de paréntesis, y la barra), entonces esto no es un legal Estudiante objeto. La forma aprobada para indicar un fallo de este tipo se establece la failbit en el objeto de entrada. Esto detendrá todas las entradas más hasta que se borre el fallo.

El siguiente paso es intentar realmente para almacenar estos valores en la Estudiante. Por ejemplo, todos los marcadores pueden haber estado presentes, pero el valor leído por el promedio de calificaciones puede haber sido 8,0, un valor que es claramente fuera de nuestro rango predefinido de 0 a 4,0. Suponiendo que la Estudiante objeto incluye controles para los valores fuera de la gama en sus métodos set, la llamada a setGPA () se producirá una excepción que se captura en el extractor. De nuevo, el extractor establece el failbit. Si el extractor de relanzamientos La excepción es responsabilidad del programador.

Es mucho mejor que depender de la setGPA () método para detectar el problema gama de implementar un control de este tipo en el propio extractor. Mejor dejar que el Estudiante oponerse a proteger su propio estado que confiar en las funciones externas.

Utilizar estos nuevos métodos

La siguiente (muy) sencilla CustomIO programa muestra cómo se utilizan estos métodos insertador y extractores. Este ejemplo, junto con la costumbre Estudiante de inserción y de extracción están disponibles en faqsalex.info:

int main (int argc, char * pargs []) {s1 Estudiante ("Davis", 123456, 3.5) -cout lt; lt; s1 lt; lt; endl-Estudiante s2 ("Eddins", 1, 3) -cout lt; lt; s2 lt; lt; endl-cout lt; lt; "Entrada de un objeto estudiante:"-cin gt; gt; s1-Si (cin.fail ()) {cout lt; lt; "estudiante de la lectura de error " lt; lt; endl-cin.clear () -} else {cout lt; lt; "Leer: " lt; lt; s1 lt; lt; endl-} cout lt; lt; "Pulse Intro para continuar ..." lt; lt; endl-cin.ignore (10, `n`) - cin.get () - volver 0-}

La salida de este programa (cuando se proporciona un estudiante legal que aparece de entrada de la siguiente manera:

Davis (123456) /3.50Eddins (000001) /3.00Input un objeto estudiante: Laskowski (234567) /3.75Read: Laskowski (234567) /3.75Press Intro para continuar ...

Observe que el estudiante Davis muestra simplemente como queríamos: la identificación del estudiante está rodeado de paréntesis, y el promedio de calificaciones aparece con dos dígitos después del punto decimal. Esto último es cierto incluso para el estudiante Eddins algo problemático.

El estudiante Laskowski se acepta como entrada, ya que tiene todas las marcas propias de un estudiante válida: paréntesis y rayas verticales en todos los lugares correctos. Echa un vistazo a lo que sucede si dejamos algo fuera, sin embargo:

Entrada de un objeto estudiante: Laskowski 234567 / 3.75Error estudiante de la lectura

Este pequeño programa muestra dos hábitos muy importantes que usted debe desarrollar:

  • Compruebe el flag de falla al llamar fallar() después de cada entrada.

  • Borrar el indicador fallar tan pronto como se haya reconocido la insuficiencia llamando claro().

    TODAS las solicitudes posteriores de entrada será ignorada hasta que haya limpiado la bandera fallar.

Artículos Relacionados