Es prácticamente imposible presentar, ya no digamos una página, sino un sitio web completo con un conjunto de ejemplos representativos para cualquier lenguaje de programación; sin embargo, se han seleccionado aquí algunos ejemplos que pudieran ser de utilidad para la familiarización inicial del lector con el lenguaje de programación C++, así como para sentar las bases que permitan comprender los ejemplos ulteriores desarrollados respecto al lenguaje.
Lectura de datos desde la terminal.
Una de las tareas más comunes para cualquier programa es la lectura de datos desde la entrada estándar (teclado). Para los programas del blog que utilizan entrada de datos, se sugiere el enfoque que se presenta en el Ejemplo Lectura.
El Ejemplo Lectura muestra en la línea 4 la inclusión de la biblioteca estándar de entrada y salida para C++: iostream.
La línea 6 le indica al compilador que debe utilizar el espacio de nombres estándar (std). Un espacio de nombres es un mecanismo para expresar un agrupamiento lógico [Stroustrup]. Es decir, si algunas declaraciones comparten desde el punto de vista lógico algunos criterios, pueden ponerse en un espacio de nombres común para establecer ese hecho.
Las líneas 8-16 definen la función principal main, la cual es el punto de entrada para los programas C++.
El Ejemplo Lectura muestra en la línea 4 la inclusión de la biblioteca estándar de entrada y salida para C++: iostream.
La línea 6 le indica al compilador que debe utilizar el espacio de nombres estándar (std). Un espacio de nombres es un mecanismo para expresar un agrupamiento lógico [Stroustrup]. Es decir, si algunas declaraciones comparten desde el punto de vista lógico algunos criterios, pueden ponerse en un espacio de nombres común para establecer ese hecho.
Las líneas 8-16 definen la función principal main, la cual es el punto de entrada para los programas C++.
La línea 9 declara y define tres variables de tipo entero, mientras que la línea 11 es la forma de decirle a C++ que envíe la cadena (cualquier expresión entre comillas dobles es una cadena) a la salida estándar; dicha cadena es la solicitud de datos (prompt). El operador "<<" tiene un uso más amplio en C++: sigue siendo el operador de corrimiento a la izquierda a nivel de bits pero, cuando se utiliza como en este ejemplo, funciona como el operador de salida; mientras que la palabra reservada cout representa un identificador asociado a la salida estándar que, usualmente es la pantalla. Con base en lo anterior, note también el uso alternativo para presentar los resultados en la línea 15.
La línea 12 es una sentencia que permite leer dos números de la entrada estándar (habitualmente el teclado). Al igual que antes, el operador ">>" sigue siendo el operador de corrimiento a la derecha a nivel de bits, pero cuando se utiliza como en este ejemplo, es el operador de entrada; mientras que la palabra reservada cin representa un identificador asociado a la entrada estándar. En general, se puede utilizar "cin >>" para leer una variable de cualquiera de los tipos básicos y también para cadenas (string).
Finalmente, la línea 14 realiza la suma y la 15 presenta el resultado. Una posible salida para el Ejemplo Lectura se muestra a continuación:
La línea 12 es una sentencia que permite leer dos números de la entrada estándar (habitualmente el teclado). Al igual que antes, el operador ">>" sigue siendo el operador de corrimiento a la derecha a nivel de bits, pero cuando se utiliza como en este ejemplo, es el operador de entrada; mientras que la palabra reservada cin representa un identificador asociado a la entrada estándar. En general, se puede utilizar "cin >>" para leer una variable de cualquiera de los tipos básicos y también para cadenas (string).
Finalmente, la línea 14 realiza la suma y la 15 presenta el resultado. Una posible salida para el Ejemplo Lectura se muestra a continuación:
Proporcione dos numeros enteros: -5 8
-5 + 8 = 3
Estructuras de control.
C++ incorpora las estructuras de control tradicionales del enfoque estructurado con algunas diferencias. Esta sección presenta un resumen necesariamente incompleto de las estructuras de control de selección y de repetición, con la principal intención de tenerlas como una referencia inmediata.
Estructuras de selección.
El Ejemplo If muestra el uso de la estructuras de selección if y los operadores relacionales (líneas 16-27), así como el uso de la estructura de selección if-else y el operador de módulo o residuo (líneas 28-33).
Los lectores familiarizados con el lenguaje de programación C notarán que tanto las estructuras de selección como los operadores relacionales son idénticos en C++, pero a diferencia de C, sí existe el tipo booleano, por lo que en C++ es válido decir que una expresión se evalúa como verdadera o falsa según sea el caso.
Una posible salida para el Ejemplo If se muestra a continuación:
Los lectores familiarizados con el lenguaje de programación C notarán que tanto las estructuras de selección como los operadores relacionales son idénticos en C++, pero a diferencia de C, sí existe el tipo booleano, por lo que en C++ es válido decir que una expresión se evalúa como verdadera o falsa según sea el caso.
Una posible salida para el Ejemplo If se muestra a continuación:
Proporcione dos numeros enteros: 4 8
Los numeros son distintos 4 != 8
4 es menor estricto que 8
4 es menor o igual que 8
8 es divisible por 4
Por otro lado, la siguiente tabla muestra la lista de operadores relacionales utilizados en C++:
Operador Descripción
== Igual que
!= Distinto de
< Menor estricto que
> Mayor estricto que
<= Menor o igual que
>= Mayor o igual que
Estructuras de repetición.
Las estructuras de repetición while, do-while y for se muestran respectivamente en los Ejemplos While, DoWhile y For.
Los Ejemplos While, DoWhile y For se explican por sí mismos. Note que en los tres ejemplos se ha utilizado el tipo de dato int para la variable de control contador. La salida de los tres ejemplos es la misma, y se muestra a continuación:
Los Ejemplos While, DoWhile y For se explican por sí mismos. Note que en los tres ejemplos se ha utilizado el tipo de dato int para la variable de control contador. La salida de los tres ejemplos es la misma, y se muestra a continuación:
1 2 3 4 5 6 7 8 9 10
El Ejemplo Arreglo muestra la creación, recorrido e impresión de un arreglo de enteros.
La línea 10 define la variable arreglo como un arreglo de enteros. Observe que el arreglo es creado con un tamaño específico (diez) que está en función de una variable, esto es válido en C++ pero no en C.
Adicionalmente se definen también un par de variables:
Por otro lado, el segundo ciclo (líneas 20-21) realiza un recorrido tradicional para la impresión del arreglo en la salida estándar. La salida del Ejemplo Arreglo se muestra a continuación:
La línea 10 define la variable arreglo como un arreglo de enteros. Observe que el arreglo es creado con un tamaño específico (diez) que está en función de una variable, esto es válido en C++ pero no en C.
Adicionalmente se definen también un par de variables:
- Un valor inicial: valor (línea 11).
- Un incremento: incremento (línea 12).
Por otro lado, el segundo ciclo (líneas 20-21) realiza un recorrido tradicional para la impresión del arreglo en la salida estándar. La salida del Ejemplo Arreglo se muestra a continuación:
Valores generados y almacenados en el arreglo:Argumentos en la línea de comandos.
1974 1996 2018 2040 2062 2084 2106 2128 2150 2172
El Ejemplo MainArgs muestra la forma de procesar los argumentos en la invocación de un programa, lo cual resultará útil y necesario en diversas ocasiones, como es el caso de algunos de los ejercicios planteados en el blog.
La variable argv es un arreglo de apuntadores a char (línea 9). El concepto de cadena difiere entre C y C++, por lo que para este ejemplo se enfatiza que argv no almacena variables de tipo string de C++. Se recomienda al lector buscar en un manual de referencia esta sutil pero importante diferencia.
La variable argc almacena el número de argumentos proporcionados en la invocación incluyendo el nombre del programa, por lo que en función de éste se procesa la lista de argumentos con un ciclo (línea 10) y se imprime en la salida estándar la lista de argumentos proporcionados, los cuales están almacenados en argv. Una posible salida del Ejemplo MainArgs se muestra a continuación:
La variable argv es un arreglo de apuntadores a char (línea 9). El concepto de cadena difiere entre C y C++, por lo que para este ejemplo se enfatiza que argv no almacena variables de tipo string de C++. Se recomienda al lector buscar en un manual de referencia esta sutil pero importante diferencia.
La variable argc almacena el número de argumentos proporcionados en la invocación incluyendo el nombre del programa, por lo que en función de éste se procesa la lista de argumentos con un ciclo (línea 10) y se imprime en la salida estándar la lista de argumentos proporcionados, los cuales están almacenados en argv. Una posible salida del Ejemplo MainArgs se muestra a continuación:
Argumento[0] = ./main_argsExcepciones.
Argumento[1] = esto
Argumento[2] = es
Argumento[3] = un
Argumento[4] = ejemplo
Argumento[5] = del
Argumento[6] = uso
Argumento[7] = de
Argumento[8] = arumentos
Argumento[9] = en
Argumento[10] = programa
No me interrumpa cuando estoy interrumpiendo.Winston S. Churchill
Las excepciones permiten una abstracción sobre el mecanismo de manejo de errores ligeros o condiciones que un programa pudiera estar interesado en atrapar y procesar.
La idea subyacente en las excepciones es separar el manejo de este tipo de condiciones o errores de la lógica de funcionamiento inherente al programa.
Una excepción es una situación anormal en la lógica de ejecución esperada por un programa. Una forma de contemplar las excepciones es como una manera de dar el control a "alguien" cuando no se puede emprender localmente ninguna acción con sentido.
Una de las intenciones de las excepciones es la de, ante una problemática determinada, tratar de solucionarla en la medida de lo posible para continuar con el programa o aplicación, y no la de terminar con la primera dificultad que se presente.
La idea subyacente en las excepciones es separar el manejo de este tipo de condiciones o errores de la lógica de funcionamiento inherente al programa.
Una excepción es una situación anormal en la lógica de ejecución esperada por un programa. Una forma de contemplar las excepciones es como una manera de dar el control a "alguien" cuando no se puede emprender localmente ninguna acción con sentido.
Una de las intenciones de las excepciones es la de, ante una problemática determinada, tratar de solucionarla en la medida de lo posible para continuar con el programa o aplicación, y no la de terminar con la primera dificultad que se presente.
Las excepciones proporcionan una manera de que el código que detecta un problema del que no se puede recuperar, pase el problema a alguna parte del sistema en la que sí sea posible hacerlo. El mecanismo de manejo de excepciones de C++ proporciona al programador una forma de tratar los errores en un lugar en donde se puede hacer con mayor naturalidad.
Un manejo completo y robusto de excepciones es una labor que, si bien su dominio no requiere de décadas, tampoco es una tarea trivial y queda fuera de los alcances de esta sección.
Para los ejemplos desarrollados en el blog se hará uso de una excepción muy simple definida de dos maneras distintas: excepcion_ED_vacia. Se trabajará con ella y describirá por primera vez en la implementación de pilas.
Un manejo completo y robusto de excepciones es una labor que, si bien su dominio no requiere de décadas, tampoco es una tarea trivial y queda fuera de los alcances de esta sección.
Para los ejemplos desarrollados en el blog se hará uso de una excepción muy simple definida de dos maneras distintas: excepcion_ED_vacia. Se trabajará con ella y describirá por primera vez en la implementación de pilas.
La relación de la jerarquía de clases en la que se encuentra la clase Exception en el contexto de C++, se expresa en un diagrama de clases de UML (Unified Modeling Language) de la siguiente figura:
Relación UML de la jerarquía de clases exception de C++ (adaptada de Stroustrup).
Espacios de nombres.
Un espacio de nombres es un mecanismo para expresar agrupamiento lógico [Stroustrup].
En este sentido, si algunas declaraciones comparten algunos criterios desde el punto de vista lógico, sería recomendable ponerlas en un espacio de nombres común para expresar ese hecho. Lo anterior podría ser una actividad que empiece a identificarse desde el diseño.
Un espacio de nombres es también un ámbito, por lo que, cuanto mayor es un programa, más útiles son los espacios de nombres para expresar las separaciones lógicas de sus partes. Los ámbitos locales, los ámbitos globales y las clases ordinarios son espacios de nombres.
Todas las declaraciones de un programa no trivial idealmente deberían estar en algún espacio de nombres cuyo identificador indique su papel lógico en el contexto del programa.
Hacia el final de la sección Implementación de herencia C++, se muestra un sencillo ejemplo de la implementación de espacio de nombres para el ejemplo de herencia desarrollado. Se recomienda también al lector, previo a revisión del ejemplo citado, la revisión de la entrada Herencia / Generalización para obtener los pormenores previos a su implementación.
Plantillas (templates).
Las plantillas se diseñaron para poder trabajar con tipos de datos genéricos. Así por ejemplo, es posible crear una plantilla de función cuya funcionalidad se puede adaptar a más de un tipo o clase sin repetir todo el código para cada tipo.
Lo anterior se puede lograr usando parámetros de plantilla. Un parámetro de plantilla es un tipo especial de parámetro que se puede usar para pasar un tipo como argumento: al igual que los parámetros de funciones normales se pueden usar para pasar valores a una función, los parámetros de plantilla también permiten pasar tipos a una función. Estas plantillas de funciones pueden usar estos parámetros como si fueran cualquier otro tipo regular.
El formato para declarar plantillas de funciones con parámetros de tipo es el siguiente:
El formato para declarar plantillas de funciones con parámetros de tipo es el siguiente:
template <class indetificador> declaración_de_función;
template <typename indetificador> declaración_de_función;
template <typename indetificador> declaración_de_función;
El uso es de class o typename es indistinto ya que ambas expresiones tienen exactamente el mismo significado para el compilador y se comportan de la misma manera. Así por ejemplo, para crear una función que determine el mayor entre dos objetos cualesquiera podríamos escribir:
template <class T>
T mayor(T a, T b){
return a > b ? a : b;
}
donde T es el parámetro de plantilla y representa el tipo (genérico) que eventualmente se especificará y operará en consecuencia como un tipo de dato regular. El uso o invocación de una función que se base en una plantilla se realiza de la siguiente manera:
nombre_de_función <tipo ó clase> (parámetros);
Así, una invocación concreta para la función definida anteriormente sería:
max = mayor <int> (x, y);
donde x, y y max son variables de tipo entero.
Cuando el compilador encuentra esta llamada a una función de plantilla, utiliza la plantilla para generar automáticamente la definición de una función que reemplaza cada ocurrencia de T por el tipo pasado como parámetro de plantilla en la invocación (int en el ejemplo) y luego la llama. Este proceso lo realiza automáticamente el compilador y es transparente para el programador.