Objetos predefinidos

C++ declara y define cuatro objetos predefinidos, uno de la clase istream, y tres más de la clase ostream_withassign estos objetos están disponibles para cualquier programa C++:

  • cin: entrada estándar: teclado.
  • cout: salida estándar: pantalla.
  • cerr: salida sin buffer a pantalla, la salida es inmediata, no es necesario vaciar el buffer.
  • clog: igual que cerr, aunque suele redirigirse a un fichero log en disco.

Objeto cout

Se trata de un objeto global definido en "iostream.h".

A lo largo de todo el curso hemos usado el objeto cout sin preocuparnos mucho de lo qué se trataba en realidad, ahora veremos más profundamente este objeto.

El operador <<

Ya conocemos el operador <<, lo hemos usado a menudo para mostrar cadenas de caracteres y variables.

ostream &operator<<(int)

El operador está sobrecargado para todos los tipos estándar: char, char *, void *, int, long, short, bool, double y float.

Además, el operador << devuelve una referencia objeto ostream, de modo que puede asociarse. Estas asociaciones se evalúan de izquierda a derecha, y permiten expresiones como:

cout << "Texto: " << variable << "\n";

C++ reconoce el tipo de la variable y muestra la salida de la forma adecuada, siempre como una cadena de caracteres.

Por ejemplo:

int entero = 10;
char caracter = 'c';
char cadena[] = "Hola";
float pi = 3.1416;
void *puntero = cadena;

cout << "entero=" << entero << endl;
cout << "caracter=" << caracter << endl;
cout << "cadena=" << cadena << endl;
cout << "pi=" << pi << endl;
cout << "puntero=" << puntero << endl;

La salida tendrá este aspecto:

entero=10
caracter=c
cadena=Hola
pi=3.1416
puntero=0x254fdb8

Funciones interesantes de cout

Hay que tener en cuenta que cout es un objeto de la clase "ostream", que a su vez está derivada de la clase "ios", así que heredará todas las funciones y operadores de ambas clases. Se mostrarán todas esas funciones con más detalle en la documentación de las bibliotecas, pero veremos ahora las que se usan más frecuentemente.

Formatear la salida

El formato de las salidas de cout se puede modificar mediante flags. Estos flags pueden leerse o modificarse mediante las funciones flags, setf y unsetf.

Otro medio es usar manipuladores, que son funciones especiales que sirven para cambiar la apariencia de una operación de salida o entrada de un stream. Su efecto sólo es válido para una operación de entrada o salida. Además devuelven una referencia al stream, con lo que pueden ser insertados en una cadena entradas o salidas.

Por el contrario, modificar los flags tiene un efecto permanente, el formato de salida se modifica hasta que se restaure o se modifique el estado del flag.

Funciones manipuladoras con parámetros

Para usar estos manipuladores es necesario incluir el fichero de cabecera iomanip.

Existen seis de estas funciones manipuladoras: setw, setbase, setfill, setprecision, setiosflags y resetiosflags.

Todas trabajan del mismo modo, y afectan sólo a la siguiente entrada o salida.

Manipulador setw

Permite cambiar la anchura en caracteres de la siguiente salida de cout. Por ejemplo:

#include <iostream>
#include <iomanip>
using namespace std;
 
int main() {
   int x = 123, y = 432;
 
   cout << "#" << setw(6) << x << "#" 
        << setw(12) << y << "#" << endl;
   return 0;
}

La salida tendrá este aspecto:

#   123#         432#
Manipulador setbase

Permite cambiar la base de numeración que se usará para la salida. Sólo se admiten tres valores: 8, 10 y 16, es decir, octal, decimal y hexadecimal. Por ejemplo:

#include <iostream>
#include <iomanip> 
using namespace std;
 
int main() {
   int x = 123;
 
   cout << "#" << setbase(8) << x 
        << "#" << setbase(10) << x 
        << "#" << setbase(16) << x 
        << "#" << endl;
   return 0;
}

La salida tendrá este aspecto:

#173#123#7b#
Manipulador setfill

Permite especificar el carácter de relleno cuando la anchura especificada sea mayor de la necesaria para mostrar la salida. Por ejemplo:

#include <iostream>
#include <iomanip>
using namespace std;
 
int main() {
   int x = 123;
 
   cout << "#" << setw(8) << setfill('0') 
        << x << "#" << endl;
   cout << "#" << setw(8) << setfill('%') 
        << x << "#" << endl;
   return 0;
}

La salida tendrá este aspecto:

#00000123#
#%%%%%123#
Manipulador setprecision

Permite especificar el número de dígitos significativos que se muestran cuando se imprimen números en punto flotante: float o double. Por ejemplo:

#include <iostream>
#include <iomanip>
using namespace std;
 
int main() {
   float x = 121.0/3;
 
   cout << "#" << setprecision(3) 
        << x << "#" << endl;
   cout << "#" << setprecision(1) 
        << x << "#" << endl;
   return 0;
}

La salida tendrá este aspecto:

#40.3#
#4e+01#
Manipuladores setiosflags y resetiosflags

Permiten activar o desactivar, respectivamente, los flags de formato de salida. Existen quince flags de formato a los que se puede acceder mediante un enum definido en la clase ios:

flag Acción
skipws ignora espacios en operaciones de lectura
left ajusta la salida a la izquierda
right ajusta la salida a la derecha
internal deja hueco después del signo o el indicador de base
dec conversión a decimal
oct conversión a octal
hex conversión a hexadecimal
showbase muestra el indicador de base en la salida
showpoint muestra el punto decimal en salidas en punto flotante
uppercase muestra las salidas hexadecimales en mayúsculas
showpos muestra el signo '+' en enteros positivos
scientific muestra los números en punto flotante en notación exponencial
fixed usa el punto decimal fijo para números en punto flotante
unitbuf vacía todos los buffers después de una inserción
stdio vacía los buffers stdout y stderr después de una inserción

Veamos un ejemplo:

#include <iostream>
#include <iomanip>
using namespace std;
 
int main() {
   float x = 121.0/3;
   int y = 123;
 
   cout << "#" << setiosflags(ios::left) 
        << setw(12) << setprecision(4) 
        << x << "#" << endl;
   cout << "#" 
        << resetiosflags(ios::left | ios::dec) 
        << setiosflags(ios::hex | 
            ios::showbase | ios::right) 
        << setw(8) << y << "#" 
        << endl;
   return 0;
}

La salida tendrá este aspecto:

#40.33       #
#    0x7b#

Manipuladores sin parámetros

Existe otro tipo de manipuladores que no requieren parámetros, y que ofrecen prácticamente la misma funcionalidad que los anteriores. La diferencia es que los cambios son permanentes, es decir, no sólo afectan a la siguiente salida, sino a todas las salidas hasta que se vuelva a modificar el formato afectado.

Manipuladores dec, hex y oct
inline ios& dec(ios& i)
inline ios& hex(ios& i)
inline ios& oct(ios& i)

Permite cambiar la base de numeración de las salidas de enteros, supongo que resulta evidente, pero de todos modos lo diré.

Función Acción
dec Cambia la base de numeración a decimal
hex Cambia la base de numeración a hexadecimal
oct Cambia la base de numeración a octal

El cambio persiste hasta un nuevo cambio de base. Ejemplo:

#include <iostream>
using namespace std;
 
int main() {
   int a = 123, c = 432, b = 543;
   
   cout << "Decimal:     " << dec 
        << a << ", " << b 
        << ", " << c << endl;
   cout << "Hexadecimal: " << hex 
        << a << ", " << b 
        << ", " << c << endl;
   cout << "Octal:       " << oct 
        << a << ", " << b 
        << ", " << c << endl;
   
   return 0;
}

La salida tendrá éste aspecto:

Decimal:     123, 543, 432
Hexadecimal: 7b, 21f, 1b0
Octal:       173, 1037, 660
Funciones ws y ends

La función ws sólo es para streams de entrada.

La función ends no tiene sentido en cout, ya que sirve para añadir el carácter nulo de fin de cadena.

Función flush
ostream& flush(ostream& outs);

Vacía el buffer de salida. Puede ser invocada de dos modos:

cout.flush();
cout << flush;
Función endl
ostream& endl(ostream& outs);

Vacía el buffer de salida y además cambia de línea. Puede ser invocada de dos modos:

cout.endl();
cout << endl;
Función width

Cambia la anchura en caracteres de la siguiente salida de stream:

int width();
int width(int);

La primera forma devuelve el valor de la anchura actual, la segunda permite cambiar la anchura para la siguiente salida, y también devuelve el valor actual de la anchura.

   int x = 23;
   
   cout << "#";
   cout.width(10);
   cout << x << "#" << x << "#" << endl; 
Función fill

Cambia el carácter de relleno que se usa cuando la salida es más ancha de la necesaria para el dato actual:

int fill();
int fill(char);

La primera forma devuelve el valor actual del carácter de relleno, la segunda permite cambiar el carácter de relleno para la siguiente salida, y también devuelve el valor actual.

  int x = 23;
  cout << "|";
  cout.width(10);
  cout.fill('%');
  cout << x << "|" << x << "|" << endl;
Función precision

Permite cambiar el número de caracteres significativos que se mostrarán cuando trabajemos con números en coma flotante: float o double:

int precision();
int precision(char);

La primera forma devuelve el valor actual de la precisión, la segunda permite modificar la precisión para la siguiente salida, y también devuelve el valor actual.

   float x = 23.45684875;
   
   cout << "|";
   cout.precision(6);
   cout << x << "|" << x << "|" << endl;
Función setf

Permite modificar los flags de manipulación de formato:

long setf(long);
long setf(long valor, long mascara);

La primera forma activa los flags que estén activos en el parámetro valor y deja sin cambios el resto.

La segunda forma activa los flags que estén activos tanto en valor como en mascara y desactiva los que estén activos en mascara, pero no en valor. Podemos considerar que mascara contiene activos los flags que queremos modificar y valor los flags que queremos activar.

Ambos devuelven el valor previo de los flags.

   int x = 235;
   
   cout << "|";
   cout.setf(ios::left, ios::left | 
      ios::right | ios::internal);
   cout.width(10);
   cout << x << "|" <<  endl;
Función unsetf

Permite eliminar flags de manipulación de formato:

void unsetf(long mascara);

Desactiva los flags que estén activos en el parámetro.

Nota: en algunos compiladores he comprobado que esta función tiene como valor de retorno el valor previo de los flags.

   int x = 235;
   
   cout << "|";
   cout.unsetf(ios::left | ios::right | ios::internal);
   cout.setf(ios::left);
   cout.width(10);
   cout << x << "|" <<  endl;
Función flags

Permite cambiar o leer los flags de manipulación de formato:

long flags () const;
long flags (long valor);

La primera forma devuelve el valor actual de los flags.

La segunda cambia el valor actual por valor, el valor de retorno es el valor previo de los flags.

   int x = 235;
   long f;
   
   cout << "|";
   f = flags();
   f &= !(ios::left | ios::right | ios::internal);
   f |= ios::left;
   cout.flags(f);
   cout.width(10);
   cout << x << "|" <<  endl;
Función put

Imprime un carácter:

ostream& put(char);

Ejemplo:

   char l = 'l';
   unsigned char a = 'a';
 
   cout.put('H').put('o').put(l).put(a) << endl;
Función write

Imprime varios caracteres:

ostream& write(char* cad, int n);

Imprime n caracteres desde el principio de la cadena cad. Ejemplo:

   char cadena[] = "Cadena de prueba";
 
   cout.write(cadena, 12) << endl;
Función form

Imprime expresiones con formato, es análogo al printf de "stdio":

ostream& form(char* format, ...);

Nota: algunos compiladores no disponen de esta función.

Ejemplo:

   char l = 'l';
   int i = 125;
   float f = 125.241;
   char cad[] = "Hola";

   cout.form("char: %c, int: %d, float %.2f, char*: %s", 
      l, i, f, cad);