5.2.2. Uso común

Como se ilustraba en el extractor de Date, debe estar alerta por las entradas erróneas. Si la entrada produce un valor inesperado, el proceso se tuerce y es difícil de recuperar. Además, por defecto, la entrada formateada está delimitada por espacios en blanco. Considere que ocurre cuando recogemos los fragmentos de código anteriores en un solo programa:

//: V2C04:Iosexamp.cpp {RunByHand}

y le proporcionamos la siguiente entrada:

12 1.4 c this is a test

esperamos la misma salida que si le hubieramos proporcionado esto:

12
1.4
c
this is a test

pero la salida es algo inesperado

i = 12
f = 1.4
c = c
buf = this 0xc

Nótese que buf solo tiene la primera palabra porque la rutina de entrada busca un espacio que delimite la entrada, que es el que se encuentra después de 'tihs.' Además, si la entrada continua de datos es mayor que el espacio reservado por buf, sobrepasamos los limites del buffer.

En la práctica, usualmente deseará obtener la entrada desde programas interactivos, una linea cada vez como secuencia de carácteres, leerla, y después hacer las conversiones necesarias hasta que estén seguras en un buffer. De esta manera no deberá preocuparse por la rutina de entrada fallando por datos inesperados.

Otra consideración es todo el concepto de interfaz de línea de comandos. Esto tenia sentido en el pasado cuando la consola era la única interfaz con la máquina, pero el mundo está cambiando rápidamente hacia otro donde la interfaz gráfica de usuario (GUI) domina. ¿Cual es el sentido de la E/S por consola en este mundo? Esto le da mucho más sentido a ignorar cin en general, salvo para ejemplos simples y tests, y hacer los siguientes acercamientos:

  1. Si su programa requiere entrada, ¿leer esta entrada desde un fichero? Pronto verá que es remarcablemente fácil usar ficheros con iostream. Iostream para ficheros todavia funciona perfectamente con una GUI.

  2. Leer la entrada sin intentar convertirla, como hemos sugerido. Cuando la entrada es algun sitio donde no podemos arriesgarnos durante la conversión, podemos escanearla de manera segura.

  3. La salida es diferente. Si está usando una interfaz gráfica, cout no necesariamente funciona, y usted debe mandarlo a un fichero (que es indéntico a mandarlo a un cout) o usar los componentes del GUI para mostrar los datos. En cualquier otra situacion, a menudo tiene sentido mandarlo a cout. En ambos casos, la funciones de formateo de la salida de iostream son muy útiles.

Otra práctica común ahorra tiempo en compilaciones largas. Consideres, por ejemplo, cómo quiere declarar los operadores del stream Date introducidos antes en el capítulo en un fichero de cabecera. Usted solo necesita incluir los prototipos para las funciones, luego no es necesario incluir la cabecera entera de <iostream> en Date.h. La práctica estándar es declarar solo las clases, algo como esto:

class ostream;

Esta es una vieja tecnica para separar la interfaz de la implementación y a menudo la llaman declaración avanzada( y ostream en este punto debe ser considerada un tipo incompleto, ya que la definición de la clase no ha sido vista todavia por el compilador).

Esto con funcionará asi, igualmente, por dos razones:

Las clases stream estan definidas en el espacio de nombres std.

Son plantillas.

La declaración correcta debería ser:

namespace std {
  template<class charT, class traits = char_traits<charT> >
    class basic_ostream;
  typedef basic_ostream<char> ostream;
}

(Como puede ver, como las clase string, las clases stream usan las clases de rasgos de caracter mencionadas en el Capítulo 3). Como puede ser terriblemente tedioso darle un tipo a todas las clases stream a las que quiere referenciar, el estándar provee una cabecera que lo hace por usted:

// Date.h
#include <iosfwd>

class Date {
  friend std::ostream& operator<<(std::ostream&,
                                  const Date&);
  friend std::istream& operator>>(std::istream&, Date&);
  // Etc.