0% encontró este documento útil (0 votos)
13 vistas61 páginas

2 Conceptos Basicos CPP

El documento presenta conceptos básicos de C++, incluyendo entrada y salida de datos, tipos de variables, y operadores. Se detallan las variables primitivas como bool, char, int, float, double y void, así como su uso y características. También se abordan temas como el casting, la entrada múltiple de datos y la declaración de arrays en C++.

Cargado por

cirovilmer2
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
13 vistas61 páginas

2 Conceptos Basicos CPP

El documento presenta conceptos básicos de C++, incluyendo entrada y salida de datos, tipos de variables, y operadores. Se detallan las variables primitivas como bool, char, int, float, double y void, así como su uso y características. También se abordan temas como el casting, la entrada múltiple de datos y la declaración de arrays en C++.

Cargado por

cirovilmer2
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd

I102 - Paradigmas de Programación

Prof. Mariano Scaramal


Ingeniería en Inteligencia Artificial
Que conceptos de C++?

• Conceptos básicos de C++:


• Entrada y Salida de datos,
• Tipos de variables,
• Operadores,
• Sentencias,
• Funciones,
• Librerías básicas,
• Comandos de preprocesador
2
Entrada y Salida de Datos
La salida y entrada de información por pantalla se realiza mediante cout y cin,
respectivamente.
Tanto cout como cin son objetos de las clases std::istream y std::ostream, las
cuales se verán luego del primer parcial.
A continuación, los dos códigos imprimen Hello, World! en pantalla. El de la
derecha, hace uso del namespace std. Esto evita repetir std:: para indicar a quien
pertenece el objeto cout y el manipulador de flujo endl.
El operador << es el operador de inserción, usado para insertar data en cout.

#include <iostream>
#include <iostream>
using namespace std;
int main(){
int main(){
std::cout << "Hello, World!" << std::endl;
cout << "Hello, World!" << endl;
return 0;
return 0;
} 3
}
Entrada y Salida de Datos (cont’d)
La entrada de información por el #include <iostream>
usuario se hace por medio de cin y el #include <string>
controlador de flujo >>. using namespace std;

En el ejemplo, el nombre ingresado int main() {


por el usuario se almacena en la string name, fullName;

variable name que es tipo string. cout << "Ingrese su nombre: ";
cin >> name;
Al ingresar el nombre y presionar cout << "Ingrese su nombre completo: ";
enter, este queda en el buffer de cin >> ws; // Elimina los whitespaces del buffer
lectura y cuando se usa nuevamente getline(cin, fullName);
cin, este leerá el enter como fin de los cout << "Hola, " << name << "!" << endl;
datos ingresados en getline. cout << "Tu nombre completo es: " << fullName << endl;

Para resolver esto, se eliminan los return 0;


whitespaces con std::cin >> std::ws; }
4
Variables Primitivas
• Las variables primitivas son las variables con las que se crean las
otras variables.
• En C++ estas son:
• bool: True (1) o False (0)
• char: carácter
• int: entero
• float: numero real de precisión simple (o single precision)
• double: numero real de precisión doble (o double precision)
• void: sin tipo, utilizado cuando una función no devuelve nada.
5
La variable tipo bool
• La misma puede definirse de #include <iostream>

distintas maneras: int main(){


bool a; // Por default un bool se inicializa con false (cero)
• El tamaño de la variable bool b = true;
bool c{false};
bool es 1 byte (aunque solo
se usa 1 bit). std::cout << "a es " << a << std::endl; // a es 0
std::cout << "b es " << b << std::endl; // b es 1
std::cout << "c es " << c << std::endl; // c es 0
• Al imprimirse, se mostrará std::cout << "b es " << std::boolalpha << b << std::endl;
como número entero, 1 para // b es true
std::cout << "Tamaño del bool es " << sizeof(b) << std::endl;
true y 0 para false. O bien // Tamaño del bool es 1
“true” o “false”, mediante return 0;
}
boolalpha,
6
La variable tipo char
• Esta variable contiene #include <iostream>

caracteres de la tabla ASCII, int main(){


char a;
como ser: char b{'+'}; // + en char
char c = 0b00101011; // + en binario
‘a’, ‘F’, ‘@’, ‘#‘, etc char d = 053; // + en octal
char e = 43; // + en decimal
char f = 0x2b; // + en hexadecimal
• Observe que estos
caracteres usan las comillas std::cout << "b es " << b << ", c es " << c << ", d es "
<< d << ", e es " << e << ", f es " << f << std::endl;
simples. std::cout << "El tamaño del char es : " << sizeof(char) <<
std::endl;

• Es una variable de 1 byte return 0;


con un rango entre -128 y }

127. b es +, c es +, d es +, e es +, f es +
El tamaño del char es: 1 7
La variable tipo char (cont’d)
• Existen los denominados “caracteres no gráficos”, los cuales son utilizados
para interpretar caracteres especiales, por ejemplo:
Carácter Representación en ASCII Valor en ASCII Secuencia de Escape
Nueva línea NL 10 \n
Tab horizontal HT 9 \t
Retroceso BS 8 \b
Retornar CR 13 \r
Signo de pregunta ? 63 \?
Comillas simples ‘ 39 \’
Comillas dobles “ 34 \”
Número octal ooo --- \ooo
Número hexadecimal hhh --- \xhhh
Carácter NULL NUL 0 \0

• Tabla ASCII: es.wikipedia.org/wiki/ASCII 8


Las variables enteras
• La tabla presenta los tipos de enteros para Windows.
• Pueden ser con o sin signo, modificando su rango.
• El rango de algunos enteros (ver Data Type Ranges ).
Tipo de Variable Bytes Rango de Valores Otros Nombres
__int8 1 -128 a 127 char, signed char, int8_t
unsigned __int8 1 0 a 255 unsigned char, uint8_t
__int16 2 -32.768 a 32.767 short, short int, signed short int
unsigned __int16 2 0 a 65.535 unsigned short, unsigned short int,
wchar_t, __wchar_t
__int32 4 -2.147.483.648 a 2.147.483.647 int, signed int, long, long int,
signed long int
unsigned __int32 4 0 a 4.294.967.295 unsigned int, unsigned long int
__int64 8 -9.223.372.036.854.775.808 a long long, signed long long, double
9.223.372.036.854.775.807
unisgned __int64 8 0 a 18.446.744.073.709.551.615 unsigned long long
long double 8/16 - 1,193932 a 1,193932 8/16 bytes para Win/Linux 9
Las variables enteras (cont’d)
#include <iostream>
• Al igual que para char,
existen distintas formas de int main(){
unsigned int a = 85; // decimal
definirlos. long long b{07747677}; // octal (usar cero antes del número)
short c = {0xA}; // hexadecimal (usar 0x)
• Si el rango es superado, una std::int16_t d = +32768;

variable signada, hará std::cout << "b es " << b << ", c es " << c << ", d es " << d <<
overflow (ver variable “d”). std::endl;
std::cout << "El tamaño del long long es: " << sizeof(long
long) << std::endl;
• Las variables __intxx son de
Microsoft, no son return 0;
}
reconocidas en todos los
sistema operativo. Utilizar b es 2.084.799, c es 10, d es -32768
sus equivalentes para Linux. El tamaño del long long es: 8
10
Las variables de punto flotante
• Las variables de punto flotante tratan de interpretar los números reales.
• En C++ existen:
o float: precisión simple con 32 bits, 8 bits en exponente y 23 bits en mantisa.
o double: precisión doble con 64 bits, 11 bits en exponente y 52 bits en
mantisa.
o long double: precisión cuádruple con 128 bits, 15 en exponente y 112 en
mantisa.

bit de bits de bits de


signo exponente mantisa
1/0
11
Las variables de punto flotante (cont’d)
Ejemplo con long double :
#include <iostream>
#include <iomanip>

using namespace std;

int main(){
long double value = 3.1415926535897932384626433832795;
cout << "El valor es: " << setprecision(30) << value << endl;
// El valor es: 3.14159265358979311599796346854
return 0;
}

Si no se utiliza setprecision el resultado en pantalla sería simplemente 3.14159,


no obstante, al procesar el número se utilizará toda la información para proveer
una aproximación al número.
12
Las variables de punto flotante (cont’d)
El cálculo del numero interpretado con un bits de signo, mantisa y exponente se
realiza con la siguiente expresión:
𝑚
𝑠 σ𝑒−1 𝑖
𝑖=0 𝐸𝑖 2 − 2
𝑒−1 −1
x = −1 2 20 + ෍ 𝑀𝑖 2− 𝑚−𝑖+1

𝑖=1

donde:
o S es el valor del bit de signo (1 o 0)
o e es el número de bits en el exponente (8, 11 o 15)
o 𝐸𝑖 es el valor de cada bit en el exponente (1 o 0)
o m es el número de bits en la mantisa (23, 52 o 112)
o 𝑀𝑖 es el valor de cada bit en la mantisa (1 o 0)
• Esto implica que hay ciertos números que no se podrán obtener exactamente.
13
Las variables de punto flotante (cont’d)
En el simple caso de utilizar #include <iostream>
una variable tipo float: #include <iomanip>
using namespace std;

int main(){
float x = 1.0;
x = x - 0.9; // Es “x” igual a 0.1?
cout << "El valor de x es: " << x << endl;
cout << "El valor de x es: " << setprecision(30) << x << endl;

x = x - 0.1; // Es “x” igual a 0.0?


El código imprime: if (x == 0.0)
cout << "El valor de x es 0.0" << endl;
El valor de x es: 0.1 else
El valor de x es: 0.100000001490116119384765625 cout << "El valor de x no es 0.0" << endl;
El valor de x no es 0.0
return 0;
}
14
El tipo void y void*
• El compilador reconocerá la leyenda void como “no tipo”.
• El tipo void suele utilizarse para crear funciones que no devuelven nada.
• En el caso de void* esto se interpreta como un puntero a una variable que no
fue definida o aún no tiene asignado un tipo.
• La familia de funciones malloc/calloc/etc devuelven void*. Es decir un puntero
a una variable que debe ser casteada o se le debe asignar un tipo:
int *myArr = (int*) malloc( size*sizeof(int) )

• De esta manera, malloc, retorna la dirección a un espacio de memoria de un


determinado tamaño (es este caso size veces un tipo int).
• El compilador necesita el tipo de variable para compilar el código y poder
recorrer el array en tamaños tipo int.
15
El tipo void*
• El puntero a void permite castear un puntero a un tipo de variable.
• En el código, la función es utilizada para imprimir distintos tipos de variables.
• No es recomendable, luego se verán otras soluciones a este problema.
#include <iostream> int main() {
int num = 42; double pi = 3.14159; char myChar = 'A';
void print_var(void* data, size_t size) {
if (size == sizeof(int)) { print_var(&num, sizeof(num));
int* int_ptr = (int*)(data); print_var(&pi, sizeof(pi));
std::cout << "Integer: " << *int_ptr << std::endl; print_var(&myChar, sizeof(myChar));
} else if (size == sizeof(double)) { std::cout << std::endl;
double* double_ptr = (double*)(data);
std::cout << "Double: " << *double_ptr << std::endl; return 0;
} else if (size == sizeof(char)) { }
char* char_ptr = (char*)(data);
std::cout << "Character: " << *char_ptr << std::endl;
} else {
El código imprime:
std::cout << "Tipo de dato no includio." << std::endl; Integer: 42
} Double: 3.14159
Character: A 16
}
Casting en C++
El lenguaje C++ realiza el cast utilizando:
static_cast<DataType>(Variable)

Este casting es más seguro dado que tiene verificación de tipo de dato.
#include <iostream>

int main() {
int n = 10; // En hexa es: 0xA
// Con el cast tradicional, compila y muestra 0xa
void* ptr = (void*)n; // Define posiciones de memoria con valores int
std::cout << ptr << std::endl;

// Con static_cast se tendrá: Invalid type conversion


void* ptr2 = static_cast<void*>(n); // No compila por esta linea

return 0;
} 17
Múltiples Entradas de Datos
• Anteriormente se vió que los datos pueden ser ingresados de a uno.
• Tener en cuenta que se aceptan distintos tipos de datos que pueden producir
comportamiento no esperado si no se considera su tipo.
#include <iostream>
#include <typeinfo>

int main(){
char c = ‘a’; int i = 0; double d = 0.0;

std::cout << "Ingrese un carácter, un entero y una variable tipo double (separados por espacios): ";
std::cin >> c >> i >> d;
std::cout << "Usted ingreso: " << c << ", " << i << ", " << "y " << d << std::endl;
std::cout << "Tipo de dato de c: " << std::typeid(c).name() << std::endl;
std::cout << "Tipo de dato de i: " << std::typeid(i).name() << std::endl;
std::cout << "Tipo de dato de d: " << std::typeid(d).name() << std::endl;
return 0;
} 18
Arrays
• Se trata de un conjunto de datos ordenados por un índice que posee una
cantidad de elementos fija y no puede ser cambiada en tiempo de ejecución.
• Al igual que en C, el índice indica el desplazamiento de la posición inicial, es
decir, el índice inicia en cero.
• Hay distintas formas de declarar un array:
int myArr[4] = {2, 3, 6, 1};
int myArr2[4] = {2};
int myArr3[] = {10, -8, 13, 17};

• En el 2do caso, se obtiene un array de 4 posiciones pero la primera es 2.


• En el 3er caso, el compilador determina que el array es de 4 posiciones.

19
Arrays (cont’d)
• Otra forma de declarar un array es definiendo su longitud pero sin hacerle una
asignación:
char myStr[20];

• Para asignarle valores, se puede iterar sobre el mismo o se puede utilizar el


objeto cin:
char myStr[20];
std::cin >> myStr;

• Es importante tener en cuenta que cin, por default, solo lee datos hasta el
primer dato tipo whitecharacter (espacio, tab, enter, etc).

20
Matrices y Arrays Multidimensionales
• Son estructuras de tamaño fijo y su asignación es similar a la de los arrays.
• Tener en cuenta que los índices comienzan desde cero.
#include <iostream>

int main(){
int myMtx[4][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}};
std::cout << myMtx[2][0] << std::endl; // Imprime el valor 7
std::cout << myMtx[1][1] << std::endl; // Imprime el valor 5
std::cout << myMtx[3][2] << std::endl; // Imprime el valor 12

return 0;
}

• En C++ moderno es aconsejable el uso del container std::array.


• Los mismos se verán más adelante con el resto de los containers.
21
std::string
• A diferencia de C, C++ provee una variable tipo string (std::string es
implementada con una clase).
• La implementación de std::string permite concatenar strings muy fácilmente
#include <iostream>
#include <string>

int main(){
std::string s;
std::string s1 = "Hello "; El código imprime:
std::string s2 = "World";
char c = '!';
s = s1;
s += s2; // Lo mismo que hacer s = s1 + s2
Hello World!
s += c; // También permite concatenar chars
std::cout << s << std::endl;

return 0;
} 22
std::string (cont’d)
• Esta clase posee distintas funciones que le permiten realizar distintas tareas:
o s.at(i): permite acceder el carácter i-esimo del string ‘s’
o s1 == s2: compara el contenido de los dos strings ‘s1’ y ‘s2’.
o s.c_str(): retorna un puntero a su primer elemento. Esta este puntero
permite utilizar el string ‘s’ como un array de chars, es útil cuando una
función requiere que se le pase un puntero a char y no un string.
o s.substr(x, y): retorna un std:string de ‘s’ que comienza en la posición x y
tiene una longitud y.
o s.find(): busca un substring en ‘s’. Si se encuentra, retorna la primer
posición de la primer ocurrencia de la substring. Si no encuentra la
substring, se retorna el valor std::string::npos.
23
Enum y class Enum
• Los enum funcionan en forma similar al lenguaje C.
• Con class, se evitan conflictos con los nombres al utilizar la referencia.
• El siguiente código imprime los valores 8 (mes de julio) y 2 (nombre Julio).
#include <iostream>

int main(){
enum class Meses {ENERO=2, FEBRERO, MARZO, ABRIL, MAYO, JUNIO, JULIO,
AGOSTO, SEPTIEMBRE, OCTUBRE, NOVIEMBRE, DICIEMBRE};
// Si Nombres no fuera class, habria conflicto por JULIO
enum class Nombres {CERGIO, JUAN, JULIO};

std::cout << static_cast<int>(Meses::JULIO) << std::endl;


std::cout << static_cast<int>(Nombres::JULIO) << std::endl;
//std::cout << Meses::MARZO << std::endl; // ESTO PRODUCE UN ERROR!
return 0;
} 24
Deducción Automática de Tipos
• C++ puede deducir en forma automática el tipo de variable usando auto.
• Para objetos, la deducción se hace mediante el inicializador.
• Hay posibilidades que si se mezclan variables (por ejemplo, int y char), el
resultado puede ser ambiguo. Usar con precaución.

#include <iostream> cout << "La variable a es tipo: " << typeid(a).name() << endl;
using namespace std; cout << "La variable f es tipo: " << typeid(f).name() << endl;
cout << "La variable g es tipo: " << typeid(g).name() << endl;
int func1 (){return 1;} cout << "El valor de g es: " << g << endl;

double func2 (){return 2.5;} // El resultado puede no ser el esperado


auto result = func2() + func1();
int main(){
auto a = 1, b = 2, c = 3; cout << "Result es tipo: " << typeid(result).name() << endl;
auto d = 4, e = 5; cout << "El valor de result es: " << result << endl;
auto f = '7'; // ASCII Dec = 55
auto g = a+b+c+d+e+f; return 0;
} 25
Operadores
• En C++ hay diferentes tipos de operadores:
1. Operador de asignación y comparación:
=, ==: asignación y comparación, respectivamente
2. Operador aritmético:
+, -, *, /, %: suma, resta, multiplicación, división y módulo,
3. Operador de bits:
&, |, ^, <<, >>, ~: AND, OR, XOR, shift izquierda, shift derecha y negación.
Cual es la diferencia entre & y &&?
4. Operador compuesto de asignación:
+=, -=, *=, /=, %=, &=, |=, ^=: realiza la operación y asigna el resultado.
26
Operadores
5. Operadores de incremento y decremento:
++i, --i: pre incremento/decremento, suma 1 y luego hace operaciones.
i++, i--: post incremento/decremento, hace operaciones y luego suma 1.

Ejemplo:
#include <iostream>
Int main(){
int x = 1, y = 1;
std::cout << x++ * y++ << std::endl; // imprime 1, pero serán x = 2 e y = 2 (1*1)
std::cout << x++ * ++y << std::endl; // imprime 6, pero serán x = 3 e y = 3 (2*3)
std::cout << --x * y++ << std::endl; // imprime 6, pero serán x = 2 e y = 4 (2*3)
std::cout << x-- * --y << std::endl; // imprime 6, pero serán x = 1 e y = 3 (2*3)
std::cout << x * y << std::endl; // imprime 3, con serán x = 1 e y = 3 (1*3)

return 0;
} 27
Sentencia Condicional
• El operador ternario: Condición ? Expresión 1 : Expresión 2
Si la condición es verdadera, la expresión 1 es ejecutada, sino, la expresión 2.
• La condición a verificar se escribe mediante los operadores lógicos.
Operador Asociatividad
Operador Operación
() Izquierda a derecha
&& AND
++, --, !, +, -, (cast), sizeof Derecha a izquierda
|| OR
*, /, % Izquierda a derecha
! Negación
+, - Izquierda a derecha
< Menor que
<, <=, >, >= Izquierda a derecha
> Mayor que
==, != Izquierda a derecha
== Igual a
&& Izquierda a derecha
<= Menor o igual a
|| Izquierda a derecha
>= Mayor o igual a
?: Derecha a izquierda
!= No es igual a
=, +=, -=, *=, /= Derecha a izquierda 28
Sentencia Condicional – if / else
• Las sentencias if/else se utilizan como en el caso de C.
• Los casos de if/else pueden ser apilados y anidados:
if/else apilados: If/else anidados:

if (condicion1){ if (condicion1){
...; if (condicion2){
} else { ...;
...; } else
if (condicion2){ ...;
...; }
} else { else {
...; ...;
} } 29
La sentencia switch
• El switch también es utilizado #include <iostream>
using namespace std;
en forma similar a C, solo que enum class COLORES : unit8_t { ROJO, VERDE, AZUL };
en C++ se pueden utilizar
int main() {
también los enum class. COLORES colorAuto = COLORES::ROJO;

• Permite evitar problemas de switch (colorAuto) {


nombres COLORES::ROJO. case COLORES::ROJO:
cout << "El auto es rojo." << endl << endl; break;
• Permite tipear los datos en el case COLORES::VERDE:
cout << "El auto es verde." << endl << endl; break;
enum: unit8_t (no es double) case COLORES::AZUL:
cout << "El auto es azul." << endl << endl; break;
default:
cout << "No es un color contemplado." << endl;
El código imprime: }
return 0;
El auto es rojo. } 30
Sentencias de Iteración - while y do/while
• Repiten una porción de código y se detiene cuando la condición se cumple (si
la terminación no se fuerza).
• Si la condición no se cumple, en el do/while, se ejecuta el contenido entre
llaves sólo una vez, mientras que en el while, no se ejecuta nunca.

sentancia1 ; sentancia1 ;
sentancia2 ; sentancia2 ;
while (condición){ do {
sentencia3; sentencia3;
⋮ ⋮
sentenciaN; sentenciaN;
} } while (condición)
31
Sentencias de Iteración - for
• El for funciona en forma similar a como funciona en el leguaje C.
• Las expresiones 1 a 2 permiten definir y modificar una variable que se puede
evaluar en la condición para continuar la iteración.

sentancia1 ;
sentancia2 ;
int N = 10;
for (expresión1; condición; expresión3){
for (int i=0; i<N; i++){
sentencia3;
std::cout << i << std::endl;

}
sentenciaN;
}

32
El for basado en rango
• Este for permite iterar sobre rangos de variables como ser un array, un
std::vector, o algún otro container.
• Usualmente el tipo de elemento se define como auto y lo que recorre es el
contenido del contenedor.

<definición de container>
for (tipo de elemento : container){
sentencia1;

sentenciaN;
}
33
El for basado en rango - Ejemplos
#include <iostream>
#include <array>

int main(){
std::array<int, 6> v = { 0, 1, 2, 3, 4, 5 }; // definición de std::array
int a[] = {0, 1, 2, 3, 4, 5};

for ( const int& i : v ) // accede por referencia constante el valor entero


std::cout << i << “ “;
std::cout << “\n”;

for ( auto i : v ) // accede por valor, el tipo de i es int


std::cout << i << “ “;
std::cout << “n”;

for ( auto n : a ) // para el array ‘a’


std::cout << n << “ “;

return 0;
}
34
Las sentencias break y continue
• La sentencia break interrumpe la iteración saliendo del ciclo de iteraciones.
• La sentencia continue interrumpe la iteración actual, pero continua con el ciclo
de iteraciones.
#include <iostream> Resultado con continue Resultado con break

int main(){ El valor de i es: 0 El valor de i es: 0


int N = 10; El valor de i es: 1 El valor de i es: 1
for (int i = 0; i<N; i++){ El valor de i es: 2 El valor de i es: 2
if (i==5){ El valor de i es: 3 El valor de i es: 3
std::cout << "Dentro del if" << std::endl; El valor de i es: 4 El valor de i es: 4
break/continue; Dentro del if Dentro del if
} El valor de i es: 6
std::cout << "El valor de i es: " << i << std::endl; El valor de i es: 7
} El valor de i es: 8
return 0; El valor de i es: 9
}
35
Try / Catch y Throw
Los comandos try y catch funcionan juntos. El comando try generará un scope
donde se verificará si el código arroja una excepción y se la manejará en la
sección de catch.
#include <iostream>

try { int main() {


// Codigo que puede llegar a arrojar una excepcion try {
} catch (exception_type e) { int x = 10, y = 0;
// Maneja la excepción de tipo exception_type if (y == 0) // Arroja un error con el texto dado.
} catch (...) { throw "Division por zero!";
// Maneja cualquier tipo de excepción (catch-all) int result = x / y;
} } catch (const char* e) { // Captura la excepcion
std::cout << "Error: " << e << std::endl;
} // Imprime el error con el texto dado en throw.

La excepción por throw mensaje, es un tipo std::cout << "El program continua..." << std::endl;
texto dado por una cadena de caracteres. return 0;
}
36
Try / Catch y Throw
• Se pueden esperar distintos tipos de errores en una parte del código.

• Para capturar distintos posibles #include <iostream>


#include <stdexcept> // Para atrapar el std::runtime_error
errores se agregan tantos catch
como errores se esperan tener. int main() {
try {
• Si la línea comentada con throw throw std::runtime_error(“Algo salio mal!");

es utilizada en vez de la del } catch (const std::runtime_error& e) {


runtime_error, la excepción es std::cout << "Runtime error: " << e.what() << std::endl;
capturada en el segundo catch. } catch (const char* e) {
std::cout << "Error: " << e << std::endl;
} catch (...) {
• Es buena práctica el utilizar un std::cout << “Arrojo una excepcion desconocida" << std::endl;
catch que permita capturar los }
return 0;
errores no esperados o } // Imprime: Runtime error: Algo salio mal!
desconocidos. 37
Funciones
• Las funciones permiten dividir el código en tareas, obteniendo así:
o Un código más fácil de leer y seguir,
o Reutilizar código,
o Reducir el mantenimiento del código al evitar código repetido.
• La definición de una función es la siguiente:
tipo_a_retornar nombre(argumentos){
sentencia1;

sentenciaN;
return myVar;
} 38
Funciones
• Al igual que en C, las funciones en C++ poseen tres partes:
1) El prototipo de la función, #include <iostream>

2) La llamada a la función, 1) int nPower(int val=0, int exp=0);


3) La definición de la función
int main(){
2) std::cout << nPower(3,4) << std::endl;
• Las funciones pueden tener valores return 0;
default en sus parámetros. }

int nPower(int val=0, int exp=0){


• En el ejemplo, se definen los valores int valPow = 1;
default como cero, para evitar entrar en 3)
for (int i=0; i<exp; i++)
valPow *= val;
el for y retornar uno (00 = 1).
return valPow;
}

39
Funciones - Recursión
• Funciones recursivas son funciones que se llaman a si mismas.
#include <iostream>
• El concepto es reducir un problema en
problemas más pequeños y similares al int nPower(int base, int exponent);
problema original.
int main() {
int x = 3, exp = 4;
• Cada llamada a la función utiliza std::cout << nPower(x, exp) << std::endl;
recursos, pudiendo generar problemas return 0;
de performance. }

• Funciones recursivas pueden ser int nPower(int val, int exp) {


if (exp == 0) {
optimizadas mediante memoización. return 1; // Case base: x^0 = 1
} else {
• Toda función recursiva debe tener un return val * nPower(val, exp - 1);
caso base que le permita terminar la }
}
recursividad y defina el caso más elemental. 40
La palabra reservada inline
• Hace el prototipo y la definición de la función en una forma especial, esto es:
inline float cube(float val) {return val*val*val;}
• La palabra inline avisa al compilador que las llamadas a la función (en este
caso cube) puede ser reemplazada por el contenido de la función.
• Usar inline no garantiza que el compilador haga el reemplazo, esto depende
del largo de la función y del nivel de optimización requerido al compilar.
• Ventaja: dado que varias tareas se realizan al llamar una función (guardar
contexto, saltar a la función, retornar, etc), el programa puede ser más rápido.
• Desventaja: el programa puede ser más grande (más código repetido).
• Se recomienda utilizarlo con funciones cortas que se usan frecuentemente.
• Ventaja frente a macros: type-safe, más fácil para el debugging y para el
mantenimiento de código. 41
Sobrecarga de Funciones
• Sobrecarga de funciones es tener funciones #include <iostream>
con los mismos nombres, pero con distintos
parámetros a pasar. int cube(int x);
double cube(double y);
• El compilador es el encargado de realizar la
llamada a la función correspondiente en int main() {
int x = 3 ;
función del tipo del parámetro pasado. double y = 5.5;
std::cout << cube(x) << std::endl;
• La sobrecarga de funciones hace más std::cout << cube(y) << std::endl;
legible el código al evitar tener distintas
funciones para las mismas tareas. return 0;
}
El código imprime: 27 int cube(int x) { return x*x*x ; }
166.375 double cube(double y) { return y*y*y; }
42
El calificador const
• Si se desea obtener un valor constante se utiliza la palabra reservada const:
const int x = 1;

• Con una constante, se puede llegar a definir el largo de un std::array:


const int N = 5;
std::array<int, N> arr = {1, 2, 3, 4, 5};

• Una vez declarada la constante, la misma debe ser inicializada y no se podrá


modificar. El intento de modificar una constante o no inicializarla resulta en un
error en tiempo de compilación:
const int N1 = 5;
const int N2; // error en tiempo de compilación
N1++; // error en tiempo de compilación
43
El calificador const con funciones
• El calificador const también puede ser usado en la lista de parámetros de una
función.
• Si el parámetro nunca se altera en la función, es buena práctica el hacerlo
constante (const también puede ser utilizado con referencias y punteros).
• Se puede usar const en el valor a retornar. Como el valor retornado es const
float, este puede ser asignado a un const float o a un float:
const float cube(const float x) {return x*x*x;}
Int main(){
float x = 3.3;
const float f1 = cube(x);
float f2 = cube(x);

return 0;
} 44
El calificador constexpr
#include <iostream>
• El calificador constexpr (C++11) se utiliza
constexpr int fib(int n) {
para indicar que se define una constante if (n == 0) return 0;
que puede ser evaluada en tiempo de if (n == 1) return 1;
compilación. return fib(n - 1) + fib(n - 2);
}
• Tiene distintos usos, en el ejemplo, se constexpr int fibonacci[10] = {
resuelve recursivamente Fibonacci del 0 fib(0), fib(1), fib(2), fib(3), fib(4), fib(5),
al 9 para completar la tabla. fib(6), fib(7), fib(8), fib(9)
};

• De esta manera, se tienen estos primeros int main() {


10 elementos calculados durante el for (int i = 0; i < 10; ++i) {
tiempo de compilación, mejorando la std::cout << fibonacci[i] << " ";
}
performance del programa. std::cout << std::endl;
}
45
El calificador constexpr

• Al utilizar constexpr, es el compilador constexpr int cube(int x){


return x*x;
quien decide de realizar la evaluación Evaluado en }
en tiempo de ejecución. tiempo
de compilación int main() {
• En el código de arriba, la dimensión int arr[cube(3)];
}
de arr es obtenida en tiempo de
compilación.
constexpr int cube(int x){
return x*x;
• En el código de abajo, dado que la }
Evaluado en
variable n es declarada como 3 en tiempo
tiempo de ejecución, la dimensión del int main() {
de ejecución
int n = 3;
array arr es evaluada en tiempo de int arr[cube(n)];
ejecución. }

46
El calificador constexpr y consteval

• En la versión C++20, la funcionalidad constexpr int sumar(int x, int y) {


de constexp fue expandida y se return x + y;
}
incluyó el calificador consteval.
consteval int multiplicar(int x, int y) {
• Con consteval, la función debe ser return x * y;
}
evaluada en tiempo de compilación.
int main() {
• Si multiply recibe un parámetro int n = 3;
definido como variable (la variable
// Evaluado en tiempo de compilación o ejecución.
entera n), se tendrá un error de int a = sumar(2, 3);
compilación debido a que no es
constante. // Debe ser evaluado en tiempo de compilación.
int b = multiplicar(2, 3);
}
47
Archivos
El tema de archivos en C++ se
introducirá brevemente en esta Indicación Descripción
sección pero se verá con std::ios::in Lectura (el default de ifstream)
mayor detalle posteriormente. std::ios::out Escritura (el default de ofstream)
Inicialmente, en C++ se hace std::ios::binary Modo binario (el modo default es
texto)
uso de dos librerías, una para
std::ios::app Modo Append (agrega datos al final
leer, ifstream, y otra para
del archivo)
escribir, ofstream, a archivos.
std::ios::ate Abre el archivo e ubica el cursor al
Los archivos pueden leerse o final del mismo (lectura y escritura)
escribirse en forma de texto o std::ios::trunc Borra el contenido del archivo a
binario de acuerdo a los flags escribir.
que se indiquen.
48
Ejemplo – Archivos de Texto
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
using namespace std;
int main() {
// Abre el archivo en modo texto para leer int main() {
std::ifstream inFile(“ArchivoTest.txt"); ofstream outFile(“ArchivoTest.txt");
if (inFile.is_open()) { if (outFile.is_open()) { // Escribe por línea de texto
std::string line; outFile << "Hola, bienvenidos a I102 PdeP!\n";
while (std::getline(inFile, line)) // Lee línea por línea outFile << "Escribir a un archivo de texto es facil.\n";
std::cout << line << '\n’; // Texto en pantalla outFile.close(); // Cerrar el archivo!!!
inFile.close(); // Cierra el archivo cout << "Archivo creado.\n";
} else } else
std::cerr << "Error el archivo no esta abierto!\n"; cerr << "Error abriendo el archivo!\n";

return 0; return 0;
} }

Leer archivo de texto Escribir archivo de texto


49
Ejemplo – Archivos Binarios
#include <iostream>
#include <iostream>
#include <fstream>
#include <fstream>
using namespace std;
using namespace std;
int main() {
int main() {
ifstream inFile("IntegerData.bin", ios::binary);
ofstream outFile("IntegerData.bin", ios::binary);
if (inFile.is_open()) {
if (outFile.is_open()) {
int nums[5];
int numeros[] = {10, 20, 30, 40, 50};
inFile.read(reinterpret_cast<char*>(nums),
outFile.write(reinterpret_cast<char*>(numbers),
sizeof(nums)); // Lee casteando a char*
sizeof(numeros)); // Escribe casteando a char*
for (int i = 0; i < 5; ++i) // Imprime los numeros leidos
outFile.close(); // No olvidar cerrar el archivo!
cout << "Numero " << i + 1 << ": " << nums[i] << endl;
cout << “Datos binarios en archivo!\n";
inFile.close(); // No olvidar cerrar el archivo!
} else
} else
cerr << "Error escribiendo al archivo!\n";
cerr << "Error abriendo el archivo!\n";
return 0;
return 0;
}
}
Leer archivo binario Escribir archivo binario 50
Comandos del Preprocesador
• Los comandos del preprocesador son comandos que se ejecutan en la etapa
de preprocesamiento y generan el código a compilar.

• Estos comandos se encuentran dentro de los archivos que ingresan al


preprocesador.

Libraries
Temp.
.cpp Preprocessing Compiler .o
file
Executable
Linker
.cpp File
Temp.
Preprocessing Compiler .o
file
.h Runtime
Libraries
51
#include
Este comando permite incluir el contenido del archivo indicado, el cual puede ser
un standard de C/C++ o un archivo definido por el usuario. Prácticamente se
puede considerar que el comando es reemplazado con el contenido del archivo.

#include <file>
Cuando se utilizan los símbolos “<>”, el preprocesador buscará los archivos en un
directorio predeterminado (standard include directories) para acceder los header
solicitados.

#include “file.h”
Cuando se utilizan comillas, el preprocesador buscará el archivo header a incluir
en el directorio del proyecto. No obstante, se puede cambiar la ubicación del
archivo agregándole el path.
52
#define
Este comando permite definir macros y constante que son reemplazados en
tiempo de compilación:

#define nombreMacro textoAReemplazar

Ejemplos:

#define PI 3.14159 // Reemplazará la palabra PI por 3.14159


#define MIN(a,b) ( ( (a) < (b) ) ? a : b ) // Macro para encontrar mínimo

En ambos casos el textoAReemplazar substituye el texto nombre del macro. En el


caso de MIN(a,b) este se reemplaza en tiempo de preprocesado pero se evalúa
en tiempo de ejecución o compilación.

53
#undef
• Este comando se utiliza para cancelar la definición de una macro previamente
definida mediante #define.

• En caso de que el comando #undef se utilice con una macro que no exista,
este será ignorado y no se observará un error.
#include <iostream>
#define PI 3.14159
#undef PI

int main () { // Error, PI no esta definido.

std::cout << "Value of PI: " << PI << std::endl;

return 0;
}
54
Instrucciones Condicionales
• #if, #elif, #else y #endif - Permite incluir o excluir código basado en la
condición provista:
#define FEATURE_1 1 // El feature 1 fue implementado
#define TESTS_FEATURE_1 1 // El feature 1 paso las pruebas
#define FEATURE_2 1 // El feature 2 fue implementado
#define TESTS_FEATURE_2 0 // El feature 2 no paso las pruebas

#if FEATURE_1 && TESTS_FEATURE_1


std::cout << “El feature 1 esta habilitado" << std::endl;
#else
std::cout << “El feature 1 esta deshabilitado" << std::endl;
#endif

#if !TESTS_FEATURE_2
std::cout << “El feature 2 no pasó las pruebas " << std::endl;
#elif FEATURE_2
std::cout << “Feature 2 esta habilitado para su instalación" << std::endl;
#endif 55
Instrucciones Condicionales (cont’d)
• #ifdef, #ifndef, #elifdef (C++23) y #elifndef (C++23) - Permite incluir o excluir
código basado en que un macro esté (#ifdef) o no esté (#ifndef – if not defined)
definido:
#define MIN_VELOC 100
#define MAX_VELOC 200
#define MIN_VELOC 100
#ifndef MAX_VELOC
#define MAX_VELOC 200
#define MAX_VELOC 150
#elifdef MIN_VELOC
#ifdef MIN_VELOC
#undef MIN_VELOC
std::cout << “Hay una velocidad mínima" << std::endl;
#def MIN_VELOC 120
#elifndef MAX_VELOC
std::cout << “No hay limites de velocidad" << std::endl;
#enfif
#endif
// Si no está definida MAX_VELOC definirla. Si
está definida eliminar definición de MIN_VEL y
definirla nuevamente como 120.

56
#error
Este comando se utiliza para generar un error de compilación con un mensaje
definido por el programador.

#define MAIN_FEATURE 1

#if MAIN_FEATURE
std::cout << “El feature principal esta habilitado" << std::endl;
#else
#error “El feature principal no esta habilitado para las pruebas”
#endif

57
#line
Se utiliza para modifica el número de linear y el nombre del archivo que reporta el
preprocesador y el compilador.
Se utiliza con código generado automáticamente para poder facilitar su
debugging.
void my_funct() {
⋮ // líneas de código generado automáticamente

#line 1000 "generated_code.cpp“


<línea de código con error>

⋮ // líneas de código generado automaticamente


}

int main() {
my_funct();
return 0;
}
58
#pragma
Esta es una directiva que se usa para proveer instrucciones especiales al
compilador, las cuales suelen ser especificas del compilador.

Indican al compilador el generar una advertencia, realizar optimización, etc.

El comando más utilizado debido a que es soportado por múltiples compiladores,


es:
#prama once

Se utiliza para asegurar que un determinado archivo header sea incluido una
única vez en la compilación.
Este comando evita que ocurran problemas por multiples inclusiones del mismo
header file.
59
Los Operadores # y ##
• El operador # remplaza el texto con el mismo texto pero entre comillas.

• Mientras que el operador ## es utilizado para concatenar dos tokens.

#include <iostream>
#include <iostream>
#define concat(a, b) a ## b
#define QUOTMRK( x ) #x
int main() {
int main () {
int xy = 100;
std::cout << QUOTMRK(HOLA C++) << std::endl;
std::cout << concat(x, y) << std::endl;
return 0;
return 0;
}
}

Resulta en la línea de código: Resulta en la línea de código:


std::cout << “HOLA C++” << std::endl; std::cout << xy << std::endl;
60
Preguntas?

61

También podría gustarte