C++

By Tomás Hernández, Posted on July 22, 2024 (2mo ago)

Se asume que antes de leer esto, tiene conocimiento básico de programación y algo de Inglés pues algunos términos no tienen una referencia directa a Español.

Compilador

C++ es un lenguaje que utiliza un compilador por detrás. Es decir, cuando nosotros necesitamos ejecutar un programa, antes de hacer esto, lo ensambla pasándolo a binario y luego ejecuta la versión .exe generada por el compilador.

Errores que captura el compilador

Convención de nombre de los archivos

El código a ejecutar debe estar en uno o más archivos diferentes. Los archivos del programa son conocidos como archivos fuente o source files.

El sufijo que indica que un archivo es de C++ es .cpp, .cp, .cxx, .cc y .C

Instrucciones

Se finalizan con un ;

Funciones

La estructura es tipoRetorno nombre(parametros){codigo} La palabra clave de retornar algo de un tipo específico es la instrucción return.

Si el tipoRetorno es void, no hace falta utilizar un return.

Función main

Siempre retorna un int. En la mayoría de los sistemas, el valor retornado en main es un indicador de estados.

Librerías

Para cargar librerías en nuestros source files utilizamos la palabra reservada include.

Ej.:

#include <iostream>

<>: Angle Brackets

Las librerías siempre deben importarse al inicio del archivo.

Librería de Entrada y Salida de Datos (IO)

IO: Input / Output.

La librería se llama iostream. Llamamos stream a una secuencia de caracteres que leemos o fue escrita desde un dispositivo IO. La convención de decirle stream viene de que los caracteres son generados y consumidos secuencialmente durante el tiempo.

Importante: iostream es una abreviación de input y output stream, pero es posible que en algunos lugares se los mencione como istream (input stream) y ostream (output stream).

Veamos un ejemplo para sumar dos números e imprimirlos en consola

#include <iostream>

int main() 
{
	std::cout << "Enter Two Numbers:" << std::endl;
	int v1 = 0, v2 = 0;
	std::cin >> v1 >> v2;
	std::cout << "La suma de los dos numeros es:" << v1 + v2 << std::endl;
	
	return 0;
}

Header

Un Header es el nombre que se encuentra dentro de los angle brackets

Operators

Importante: Si en una línea aparece más de un << o >> entonces, se dividen en operaciones atómicas.

#include <iostream>

int main() 
{
	std::cin >> v1 >> v2

    equivale a 
    (std::cin >> v1) >> v2

    que a su vez equivale a 
    std::cin >> v1
    std::cin >> v2
}

Manipulator

endl: Tiene el efecto de terminar la ejecución de la línea actual y limpiando el buffer asociado a ese dispositivo.

Importante: Los programadores suelen agregar print mientras debuggean. Esas instrucciones siempre deben limpiar el stream. Caso contrario, si el programa crashea la salida puede haber quedado en el buffer llevándonos a inferencias incorrectas sobre por qué el programa crasheó.

Namespaces

Nos permiten evitar colisiones con los nombres que definimos y los usos de esos mismos nombres dentro de una biblioteca.

namespace::funcion

Comentarios

//: Comentario de línea

/* */: Comentario de bloque

//Esto es un comentario

o

/*
 *  Hola esto es un comentario
 *  pero con múltiples líneas.
*/

Importante: No es posible meter un comentario dentro de otro.

Estructuras de Control

Antes de explicar cualquier estructura de control es necesario entender para qué sirve el operador == en C++.

El operador de == indica la comparación por valor, y devuelve un valor booleano true o false.

While

    while(condition) {
        statement
    }

Ej de uso:

   int found = 0;
   int i = 0; 
   while(found == 0 && i!=10) {
        if(found){
            found = 1;
        }
        ++i;
   }

Importante: Recuerde verificar que el while es correcto y efectivamente termina.

Nota: ++i equivale a decir i = i+1;

For

    for(variable; limite; ++variable) {
        statement
    }

Ej de uso con una suma de gauss ineficiente:

    int sum = 0;
    for(int i = 0; i<10; ++i) {
        sum += i;
    }

Leyendo una desconocida cantidad de entradas

Utilizamos un while con un std::cin. El ingreso de información finaliza cuando llegamos a un end-of-file o encontramos un input que no es del tipo que esperamos.

En Windows, ejecutamos el end-of-file presionando CTRL + Z (en la terminal se mostrará ^Z) y luego, enter.

En sistemas UNIX, incluyendo Mac OS X es usualmente control-d. Ej.:

    int value = 0, sum = 0;  
    while(std::cin >> value){
        sum+=value;
    }
    std::cout << "La suma de los numeros ingresados es " << sum << std::endl;

Estructuras para Control de Flujo

If, Else If, Else

Es la estructura de control de flujo más común. El If/Else If llevan una guarda que indica cuando debe ejecutarse mientras que el Else se ejecuta cuando no sucede ni el if ni el else if.

Importante: Si sabemos que los casos no pueden pasar a la vez, es mejor utilizar un if else que if's separados pues los if se evalúan siempre.

Good To Know: No es necesario que un if tenga un else.

Ej.:

    int value = 0;
    if(value == 0){
        std::cout << "Hola, desde el if";
    }else if(value == 1){
        std::cout << "Hola, desde el else if";
    }else{
        std::cout << "Hola desde el else";
    }

    En este caso, entrará al if pues value = 0.
    Si value fuese uno, entraría al else if.
    Si value no es ni 0, ni 1, entonces entra al else.

Clases

Definimos nuestras estructuras de datos usando clases. Una clase define un tipo con una colección de operaciones relacionadas con ese tipo.

Un enfoque principal del diseño de C++ es hacer posible definir tipos de clases que se comporten tan naturalmente como los de los tipos incorporados.

Las clases, las definimos en un header. El sufijo para los archivos de headers es .h pero algunos programadores prefieren .H, .hpp o .hxx. Si bien el compilador no le importa la forma de los nombres de los headers, los IDE si le dan importancia.

Importante : Para usar una clase no necesito saber cómo está implementada sino solamente qué operaciones tiene y cómo las tengo que usar (un TAD, guiño guiño).

Cada clase define un tipo, el nombre del tipo es el mismo que el nombre de la clase.

Tipos

Pasaje por copia o referencia en C++

Todos los tipos en C++ se pasan por copia (valor). Sin embargo, hay dos formas de mandarlo por referencia.

Consideremos una funcion que recibe un parámetro n de cualquier tipo.

Veamos ahora sí unos ejemplos

Pasaje por defecto (la función obtiene copia/valor):
    int haceAlgo(int n) {
        n = 5; //n solo cambia en el ámbito de la función. No cambió en main.
        return 0; 
    }

    int main(){
        int n = 4;
        haceAlgo(n);
        return 0;
    }

    En este caso, n pasa por copia/valor.
Pasaje por referencia (la función obtiene directamente el objeto original)
    int haceAlgo(int& n) { //Llega alias del objeto original.
        n = 5; //Cambió n de main.
        return 0; 
    }

    int main(){
        int n = 4;
        haceAlgo(n); //Pasa referencia de n.
        return 0;
    }

Cuando en la función recibimos la referencia (&), tenemos solamente el objeto. No tenemos que preocuparnos por posibles valores null.

Pasaje por referencia usando punteros (la función obtiene la dirección donde está el objeto original)
    int haceAlgo(n* memo) { //Llega puntero de la memoria.
        *n = 5; //Cambió n de main.
        return 0; 
    }

    int main(){
        int n = 4; 
        haceAlgo(&n); //Envía referencia de la variable.
        return 0;
    }

Cuando en la función recibimos el puntero (*), tenemos más que el objeto original para modificar. Tenemos que preocuparnos por posibles valores null.

¿Qué tengo que usar? & vs *

Conclusión : A menos que necesite manejar mucho la memoria a bajo nivel, utilice &.

Importancia de los tipos

Los tipos determinan el significado de la información y las operaciones en nuestros programas.

Tipos Primitivos en C++ (Built-in Types)

Tipos Con Signo y Sin Signo (Signed & Unsigned Types)

Recordemos que al igual que en diferentes arquitecturas como por ejemplo Risc-V, la representación en sin signo solo representa números positivos (ocupando todos los bits disponibles) mientras que en la representación con signo representa tanto números positivos como negativos (tomando el primer bit como el signo).

Números
Los tipos int, short, long y long long son signed. Para poder tratarlos como tipos sin signo, tenemos que agregar antes del tipo la palabra unsigned .

    int main() {
        unsigned int edad = 0; 
    }

Caracteres
Existen tres tipos diferentes: char, signed char y unsigned char.

Optimización con los tipos en C++
  1. Usá tipos unsigned si sabés que los valores no pueden ser negativos.
  2. Usá int para cualquier tipo de entero. short suele ser muy chico, y en la práctica long tiene el mismo tamaño que int . Si int no es suficiente, usar long long .
  3. No utilizar char o bool en expresiones aritméticas. Solamente usarlas para almacenar caracteres o valores de verdad. Utilizar caracteres son muy problemáticos porque algunas computadoras los toman como signed y otras como unsigned .
  4. Para cálculos muy precisos, utilizar el tipo double en vez de float . Es más, algunas computadoras funcionan más rápido calculando en double que en float.

Conversion de Tipos

Suceden automáticamente cuando usamos un objeto de un tipo donde se está esperando un objeto de otro tipo. En C++ algunos tipos están relacionados con otros. Dos tipos están relacionados cuando hay una conversión entre ellos.

Conversiones Implícitas

Suceden sin el conocimiento del programador. Es decir, la hace C++ a través del compilador.

La mayoría de conversiones tratan de mantener a precisión si es posible.

Las conversiones implícitas ocurren cuando

  1. En las guardas, las expresiones nonbool se convierten a bool.
  2. En las inicializaciones, las variables ocurren con el tipo que se le colocó; En asignaciones, el valor que se le quiere asignar se convierte al tipo de la izquierda.
    • int i -> i es de tipo int
    • int i = 4.1523 -> 4
  3. En expresiones aritméticas y expresiones relacionales con operandos de tipos mixtos, los tipos se convierten a un tipo común.

Conversiones Aritméticas

Asignar un tipo aritmético a otro