#include <vector>
#include <iostream>
#include <algorithm>
int
main()
{
int n, t;
std::cout << "Introduce dos numeros separados por espacios ? ";
std::cin >> n >> t;
std::cout << "Has introducido " << n << " y " << t << std::endl;
std::vector<int> a(10);
std::cout << "Introduce 10 numeros separados por espacios ? ";
for (auto& v : a) std::cin >> v;
for (auto iter = a.begin(); iter != a.end(); iter++)
std::cout << *iter << " ";
std::cout << std::endl;
return 0;
}En la versión C++ hemos utilizado el equivalente a scanf
y pritnf, que para C++ es cout y
cin. cin y cout son realmente dos
objetos de las clase llamada istream y ostream
respectivamente. Estas clases sobrecargan el operador
<< y >> para leer y escribir datos
en la consola. Personalmente, la sobrecarga de este operador me resulta
extraña… pero así ha sido desde los principios de C++. Estos operadores
se encargan de convertir los datos automáticamente, a partir de los
tipos de las variables que intercalamos entre ellos.
Aunque no lo hayamos visto aún, C++, al igual que muchos lenguajes orientados a objetos, nos permite sobrecargar operadores, esto es, proporcionar nuestro propio código para que operadores estándar operen de forma distinta. Así es como (junto con el polimorfismo) estos lenguajes consiguen que cuando “sumamos” dos cadenas de caracteres las concatenemos o hagamos cualquier otra cosa que nos apetezca. Esto es bastante común en C++ y aunque hace que el código sea en generar más “legible”, en ocasiones puede resultar muy confuso o requerir un conocimiento profundo del código que estás utilizando.
Si bien, podríamos haber escrito el programa utilizando un array estándar como el de la versión C, hemos vuelto a utilizar un objeto, un vector en este caso, y de esta forma ilustrar el uso de los iteradores. De lo contrario el código C y C++ serían prácticamente idénticos.
La línea
std:vector<int> a(10)hace uso de un template o plantilla para generar un vector de enteros. El<int>es el parámetro del template. Estos templates se instancian en tiempo de compilación, momento en el cual, el compiladore generará una nueva clase de vectores de valores enteros (llamémoslaiVectoraunque os aseguro que el nombre real es bastante más raro) y la línea anterior pasaría a ser algo así comoiVector a(10).También observad que el número de elementos se pasa entre paréntesis y no corchetes. Aquí no estamos declarando un array, sino que estamos llamando a la función de la clase llamada
constructorque inicializa el objeto. En este caso, reservando memoria para 10 enteros, entre otras cosas.
La librería estándar C++ ofrece una amplia y potente variedad de
clases para definir y manejar estructuras de datos. Las estructuras
complejas como vectores en este caso, suelen ofrece
iteradores. Los iteradores son objetos que nos permiten recorrer los
elementos de la estructura de datos sin necesidad de conocer los
detalles de su estructura interna. Como podemos ver, el iterador nos
ofrece funciones para obtener el primer y último elemento, además de
sobrecargar el operador ++ para permitirnos movernos por la
estructura de datos y el oeprador * para acceder a los
datos.
De esta forma, nuestro programa principal no necesita saber si el vector está almacenado en un array, en un bloque de memoria consecutivo, o en una lista enlazada.
Las clases iterador nos ofrecen muchos más métodos para navegar las estructuras de datos (
prev,next,advance,…). Existen distintos tipos de iteradores que ofrecen distintas posibilidades, en general, sobrecargando distintos operadores.
Este programa utiliza la forma foreach de
for y por tanto necesitamos compilar el programa para C++11
o superior, lo que podemos hacer de la siguiente forma:
g++ -std=c++11 -o input input.cpp
El objeto cin nos ofrece cierta funcionalidad para
detectar errores en la entrada. Veamos este fragmento de código:
std::cout << "Introduce un Numero: "
std::cin >> n
if (std::cin.fail()) {
std::cin.clear(); // Limpia el indicador de error
std::cin.ignore (std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "Por favor introduzca un número";
}La llamada std::cin.fail() devuelve el valor verdadero
si la operación de entrada ha fallado, lo cual puede ocurrir porque
hemos introducido una cadena de caracteres, o usado un formato no
soportado. Esto activa el flag de error que indica que se ha producido
un error durante la lectura.
En ese punto los caracteres leídos del usuario todavía se encuentra
en el buffer de lectura, lo que significa que si volvemos a intentar
leer un número, cin >> fallará de nuevo.
std::cin.ignore nos permite eliminar los datos
problemáticos del buffer de entrada.
std::cin.ignore (std::numeric_limits<std::streamsize>::max(), '\n');Esta línea ignora hasta un máximo de
std::numeric_limits<std::streamsize>::max() que viene
a ser algo así como el tamaño máximo de datos leídos o hasta que se
encuentre el fin de línea. O en otras palabras, descarta el resto de la
línea. Si no hacemos esto, la próxima lectura de datos volverá a
encontrarse con los datos que provocaron el error inicial y nuestro
programa entraría en un bucle infinito intentando parsear una y otra vez
la misma cadena.
Además es necesario borrar el indicador de error para que la próxima
línea se pueda leer normalmente usando
std::cin:clear().
SUMARIO
- Podemos leer datos en nuestros programas usando el objeto
ciny el operador>> - Al igual que en C, si quieres más control sobre la validez de los datos es mejor escribir tus propios parsers.
- Elementos de la librería estándar como iteradores o plantillas simplifican mucho nuestros programas
■
