Para sobrecargar un extractor, se emplea en general la misma aproximación que se ha seguido para sobrecargar un insertador. Por ejemplo, este extractor admite coordenadas en 3-D. Obsérvese que además se las pide al usuario.
Los extractores deben proporcionar una referencia de un objeto del tipo istream. Además, el primer parámetro tiene que ser una referencia de un objeto del tipo istream. Observe que el segundo parámetro es una referencia. Esto es necesario para que su valor pueda ser modificado. La forma general de un extractor es la que se muestra a continuación:
Analogamente a los insertadores, las funciones de extractor no pueden ser miembros de la clase sobre la cual están diseñados para operar. Pueden ser friends, como se muestra en el ejemplo, o pueden ser simplemente funciones independientes.
Exceptuando el hecho de que hay que proporcionar una referencia de un objeto del tipo istream, se puede hacer lo que se quiera dentro de la función de extracción. Sin embargo, en aras de la estructura y de la claridad, lo mejor es limitar las acciones de los extractores a la operación de introducción de datos.
Como ya es sabido, si se usa printf(), se puede controlar el formato de la información que se muestra en la pantalla. Por ejemplo, se pueden especificar las amplitudes de los campos, y el ajuste a la izquierda o a la derecha. Se puede obtener el mismo tipo de formato utilizando la aproximación de C++ a la E/S. Hay dos maneras de dar formato a la salida. La primera utiliza funciones miembro de la clase ios. La segunda utiliza un tipo especial de función denominada manipulador. Vamos a empezar examinando los formatos que utilizan funciones miembro de ios, y después hablaremos de los manipuladores.
La enumeración que puede verse a continuación está definida en IOSTREAM.H:
Los valores que se definen en esta enumeración se utilizan para activar o desactivar los indicadores que controlan algunos de los aspectos en que se da formato a la información en un stream.
Cuando el indicador skipws está activado, los caracteres de espacio en blanco (los espacios, tabuladores y nueva línea) se descartan cuando se hace una entrada procedente de un stream. Cuando skipws se pone a cero, los caracteres de espacio en blanco no se descartan.
Cuando el indicador left están activado, la salida se ajusta a la izquierda. Cuando está activado right, la salida se ajusta a la derecha. Cuando está activado el indicador internal, entonces los valores numéricos se rellenan para completar un campo insertando espacios entre el signo o carácter de base que haya. (La forma de especificar la amplitud de un campo se verá en breve.) Por defecto, los valores numéricos se muestran en la base en que estén representados. Sin embargo, se puede ignorar este comportamiento que se produce por defecto. Por ejemplo, para escribir algo en decimal, active el indicador dec. Si se activa oct, se da lugar a que la salida se muestre en octal. Si se activa hex, se hace que la salida se muestre en hexadecimal. Si se activa showbase, se da lugar a que se muestre la base de los valores numéricos.
Por defecto, cuando se muestra la notación científica, la "e" va en minúsculas Además, cuando se muestra un valor hexadecimal, la "x" va en minúsculas. Cuan do uppercase está activado, se muestran en mayúsculas estos caracteres. Al activar showpos se consigue que se muestre un signo más a la izquierda delante de los valores enteros positivos. Si se activa showpoint, se da lugar a que se muestre un punto decimal y una cola de ceros para toda la salida de coma flotante, sea o no necesario.
Al activar el indicador scientific, los valores de coma flotante se muestran utilizando notación científica. Cuando se activa fixed, los valores de coma flotante se muestran utilizando la notación normal, y por defecto se muestran seis decimales. Cuando no está activado ninguno de estos indicadores, el compilador selecciona un método adecuado.
Por razones que van más allá del alcance de estos apunten, el rendimiento del sistema de E/S de C++ mejora cuando unitbuf está activado. Este indicador está activado por defecto en Turbo C++.
Cuando stdio está activado, todos los streams se vuelcan cada vez que hay una salida. Volcar un stream hace que se escriba la salida en el dispositivo físico que este asociado al stream. Los indicadores de formato están contenidos en un entero long. Para activar un indicador, se utiliza la función setf(), cuya forma más común es la que se muestra a continuación:
Esta función proporciona los valores anteriores de los indicadores de formato y activa los indicadores que se especifiquen en indicadores. Por ejemplo, para activar el indicador showbase, se puede utilizar esta sentencia:
Aquí, stream es el stream que deba ser afectado. Por ejemplo, este programa activa tanto el indicador showpos como el scientific.
La salida que produce este programa es la que se muestra a continuación:
Utilización de la biblioteca de clases de E/S de C++ 453
Se puede hacer un OR conjunto de tantos indicadores como se desee en una misma llamada. Por ejemplo, se puede modificar el programa de forma que sólo se haga una llamada a setf(), haciendo un OR de scientific y showpos, como se indica a continuación:
Para desactivar un indicador, se utiliza la función unsetf(), cuyo prototipo se muestra a continuación:
La función proporciona los valores anteriores de los indicadores y desactiva aquellos indicadores que estén especificados en indicadores. A veces es útil conocer los valores en curso de los indicadores. Se pueden obtener los valores en curso de los indicadores utilizando la función flags(), cuyo prototipo es el que se muestra a continuación:
Esta función proporciona el valor en curso de los indicadores con respecto al stream asociado. Esta forma de flags() fija como valores de los indicadores aquellos que estén especificados en indicadores, y proporciona los valores anteriores de los indicadores:
Para ver la forma en que funcionan flags() y unsetf(), examine este programa. Contiene una función llamada mostrarindicadores() que muestra el estado de los indicadores:
Cuando se ejecuta, este programa produce la siguiente salida:
Además de dar valores a los indicadores de formato, se puede definir también la amplitud del campo, el carácter que se va a utilizar como relleno, y el número de dígitos que se van a mostrar después del punto decimal, utilizando las funciones siguientes:
La función width() proporciona la amplitud actual del campo y da a la amplitud del campo el valor lon. Por defecto, la amplitud del campo varía, dependiendo del número de caracteres que se necesiten para representar los datos. La función fill() proporciona el carácter de relleno en curso, que por defecto es el espacio, y hace que el carácter de relleno en curso pase a ser car. El carácter de relleno es el carácter que se usa para rellenar la salida de modo que se complete la amplitud de campo especificada. La función precision() proporciona el número de dígitos que se muestran después del punto decimal y da a ese valor el valor num. Véase un programa que hace una demostración de estas tres funciones:
El sistema de E/S de C++ contiene una segunda forma de alterar los parámetros de formato de un stream. Esta forma utiliza funciones especiales llamadas manipuladores, que se pueden incluir en una sentencia de E/S. Los manipuladores estandard se muestran en la Tabla 2~1. Para acceder a estos manipuladores, es preciso incluir IOMANIP.H en el programa. Todos los manipuladores tienen como argumento el stream al cual estén afectando, y proporciona ese mismo stream. De esta manera, se puede utilizar un manipulador como parte de una expresión de E/S. Véase un ejemplo de programa que utiliza manipuladores para cambiar el formato de la salida:
El programa produce la salida siguiente:
Obsérvese la forma en que aparecen los manipuladores en la cadena de operaciones de E/S. Observase también que cuando un manipulador no admite argumentos, tal como el endl() del ejemplo, no va seguido por paréntesis. La razón de esto es que lo que se pasa al operador << sobrecargado es la dirección de la función.
Este programa utiliza setiosflags() a fin de activar los indicadores scientific y showpos:
Es posible crear funciones manipuladoras propias. Las más fáciles de crear son aquellas que no admiten argumentos, y éste es el tipo de manipuladores que vamos a aprender a crear aquí. (La creación de manipuladores parametrizados va más allá del alcance de estos apuntes.) Todas las funciones de manipulación de salida que no tienen argumentos tienen el esqueleto siguiente:
Aquí, nombre_manipulador es el nombre del manipulador. Es importante entender que aunque el manipulador tiene como argumento único un puntero del stream sobre el cual actúa, no se utiliza ningún argumento cuando se inserta el manipulador en una operación de salida.
Este programa crea un manipulador llamado preparar() que activa el ajuste a la izquierda, da a la amplitud del campo el valor 10 y especifica que el carácter de relleno va a ser el signo de dólar:
Los manipuladores a la medida son útiles por dos razones. En primer lugar, quizá se necesite llevar a cabo una operación de E/S en un dispositivo para el cual no son aplicables ninguno de los manipuladores predefinidos; por ejemplo, un trazador. En este caso, crear manipuladores propios hará cómodo llevar una salida al dispositivo. En segundo lugar, quizá se encuentre con que está repitiendo la misma secuencia de operaciones muchas veces. Se pueden consolidar todas estas operaciones en un solo manipulador, como mostraba el programa anterior.
Todos los manipuladores de entrada que no admiten argumentos tienen el esqueleto que se muestra a continuación: