Escribir encargo i / o

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

Crear la clase

Crea tu clase sin que respecta a la entrada o salida. Incluir obtener y conjunto funciones para la 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:

clase Student {public: Estudiante explícita (const char * pszName = "", de la identificación de largo = 0, el doble GPA = 0.0) - // el get y funciones establecidas para este classstring getName () setName-const void (cadena s) -long getID () const void SETID (larga NID) -doble getGPA () setGPA-const void (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 del insertador y extractor.

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

Crear un sencillo de inserción

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

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

El insertor se declara con el tipo de devolución ostream y devuelve el objeto pasado a ella. De lo contrario, un comando como el siguiente no iba a funcionar:

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

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

La implementación de este dispositivo de inserción es directa (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 () - regresar salida}

Pruébelo y hacer ajustes

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

// CustomIO - desarrollar un insertador y extractores de encargo # include #include #include #include "student.h" using namespace std-int main (int argc, char * pargs []) {s1 Estudiante ("Davis", 123 456, 3.5) -cout lt; lt; s1 lt; lt; endl-Student 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 la siguiente salida:

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

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

  • # 42-A de la escuela a la que los ID de los estudiantes son seis dígitos. Si el número es inferior a un total de seis dígitos, entonces el número debe ser rellenada por la izquierda con ceros.

  • Promedios de # 42-grado que 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 querías salida de un parámetro entero está en formato hexadecimal. Los usuarios del insertor 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 regresar de nuestra inserción.

Una versión de la insertador gussied aparece como sigue:

ostream operatorlt; lt; (ostream cabo, Estudiante const s) {cabo lt; lt; s.getName () lt; lt; "(" - // Forzar el id de ser un niño de seis dígitos fieldchar prevFill = out.fill ('0') - out.width (6) salida privado lt; lt; s.getID () - out.fill (prevFill) - // ahora la 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 (prev) -Retorno salida}

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

El ancho de campo se aplica sólo a la siguiente salida por lo que es importante establecer este valor inmediatamente antes de que el campo que desea impactar. Debido a que tiene una duración de sólo un campo, no es necesario registrar y restaurar el ancho de 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 para 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. Observe que en la creación del formato de salida para mi Sstudiantes objeto, el programador ha añadido ciertas marcas especiales que permitan un extractor para asegurarse de que lo que está leyendo es en realidad un Estudiante. Por ejemplo, se incluye entre paréntesis el carné de estudiante y una barra entre éste y el PAM.

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

  • # 42-Lea el nombre (una cadena de caracteres).

  • # 42-Leer un paréntesis abierto.

  • # 42-Leer un ID (un número entero).

  • # 42-Leer un paréntesis cerrado.

  • # 42 Leer una barra.


  • # 42-Lea el GPA (un número de punto flotante).

Tendrá que hacer esto mientras todo el tiempo ser conscientes de si se produce un problema de formato. Lo que sigue es mi versión del extractor del Estudiante:

istream operador >> (istream en, Estudiante s) {// leer los valores (ignorar el espacio en blanco extra) cadena de nombre de larga nID doble DGPA-char openParen = 0, closedParen = 0, slash = 0-ios_base :: fmtflags prev = in.setf (ios_base :: skipws) -en nombre >> >> >> openParen nID >> closedParen >> recortar >> DGPA-in.setf (prev) - // Si los marcadores no coinciden ... si (openParen = '(' || closedParen = ')' || slash = '/') {// ... entonces 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- } return in-}

Este insertador comienza por la lectura de cada uno de los campos previstos como se describe anteriormente en el diagrama de flujo. Si alguno de los caracteres de marcador no se encuentra (el paréntesis abierto, cerrado el paréntesis, y barra), entonces esto no es un legal Estudiante objeto. La forma aprobado para indicar un fallo de este tipo se estableció el failbit en el objeto de entrada. Esto detendrá todas las entradas más hasta que el fallo se borra.

El siguiente paso es tratar realmente para almacenar estos valores en la Estudiante. Por ejemplo, todos los marcadores pueden haber estado presentes, pero el valor leído para el promedio de calificaciones puede haber sido 8,0, un valor que está claramente fuera de nuestro rango predefinido de 0 a 4,0. Suponiendo que la Estudiante objeto incluye controles para los valores fuera de rango en sus métodos set, la llamada a setGPA () lanzará una excepción que se captura en el extractor. Una vez más, el extractor establece el failbit. Si el extractor vuelve a lanzar la excepción es hasta el 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. Es mejor dejar que el Estudiante oponerse a proteger su propio estado de depender de funciones externas.

Use estos nuevos métodos

La siguiente (muy) simples CustomIO programa muestra cómo se utilizan estos métodos de inserción y extractores. Este ejemplo, junto con la costumbre Estudiante insertor y campana extractora están disponibles en Dummies.com:

int main (int argc, char * pargs []) {s1 Estudiante ("Davis", 123 456, 3.5) -cout lt; lt; s1 lt; lt; endl-Student s2 ("Eddins", 1, 3) -cout lt; lt; s2 lt; lt; endl-cout lt; lt; "Introducir un objeto estudiante:" - cin >> s1-si (cin.fail ()) {cout lt; lt; "Estudiante de 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 como aparece de entrada como sigue:

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

Observe que el estudiante Davis muestra tal y 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. Este ú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 barras en todos los lugares correctos. Echa un vistazo a lo que sucede si dejamos algo fuera, sin embargo:

Entrada de un objeto estudiante: Laskowski 234,567 / 3.75Error estudiante lectura

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

  • Compruebe la falla bandera llamando fallar () después de cada entrada.

  • Desactive la bandera fallar tan pronto como se haya reconocido la insuficiencia llamando claro().

    TODAS las solicitudes posteriores de entrada se ignoran hasta que haya limpiado la bandera fallar.




» » » » Escribir encargo i / o