Capítulo 2: Operadores
Los operadores son los símbolos que te permiten manipular datos: sumar números, comparar valores, combinar condiciones lógicas. En C++ hay muchos tipos de operadores, y entender cómo funcionan es esencial para escribir código efectivo.
Objetivos
- Dominar los operadores aritméticos y sus particularidades
- Entender la diferencia entre pre-incremento y post-incremento
- Usar operadores de comparación y lógicos correctamente
- Conocer operadores bit a bit para manipulación de bajo nivel
- Comprender la precedencia de operadores
Operadores aritméticos
Los operadores aritméticos básicos funcionan como esperarías en matemáticas:
int a = 10;
int b = 3;
int suma = a + b; // 13
int resta = a - b; // 7
int multiplicacion = a * b; // 30
int division = a / b; // 3 (división entera)
int modulo = a % b; // 1 (residuo)
std::cout << "División: " << division << std::endl; // 3
std::cout << "Módulo: " << modulo << std::endl; // 1 División entera vs división de punto flotante
Un detalle muy importante: cuando divides dos enteros en C++, el resultado es un división entera , no un número decimal.
// División entera trunca hacia 0
int resultado1 = 10 / 3; // 3 (no 3.333...)
int resultado2 = -10 / 3; // -3 (no -3.333...)
// Para obtener resultado decimal, usa float o double
double resultado3 = 10.0 / 3.0; // 3.333333...
double resultado4 = 10 / 3.0; // 3.333333... (uno es double)
Este es uno de los errores más comunes en C++ para principiantes. Si calculas
1 / 2 esperando 0.5, obtendrás 0.
Para evitarlo, asegúrate de que al menos uno de los operandos sea de punto
flotante: 1.0 / 2 o 1 / 2.0 o static_cast<double>(1) / 2.
El operador módulo (%)
El operador % (módulo) te da el residuo de una división entera.
Es extremadamente útil para:
- Verificar si un número es par o impar:
x % 2 == 0 - Ciclar valores dentro de un rango:
indice % tamaño - Extraer dígitos de un número
¿Por qué 10 % 3 da 1?
Porque 10 dividido entre 3 es 3 con un residuo de 1:
10 = 3 × 3 + 1
El módulo te da ese residuo: 1.
Operadores de incremento y decremento
Los operadores ++ y -- incrementan o decrementan una
variable en 1. La diferencia entre pre-incremento
(++x) y post-incremento
(x++) es crucial:
int x = 5;
// Pre-incremento: incrementa ANTES de usar el valor
int a = ++x; // x = 6, a = 6
// Post-incremento: usa el valor ANTES de incrementar
int y = 5;
int b = y++; // b = 5, y = 6
// Lo mismo aplica para decremento
int z = 10;
int c = --z; // z = 9, c = 9
int d = z--; // d = 9, z = 8 ¿Cuál es más eficiente: ++x o x++? Intermedio
Para tipos primitivos como int, ambos son igual de eficientes porque
el compilador los optimiza.
Pero para objetos complejos (como iteradores), ++x puede ser más
eficiente porque x++ necesita crear una copia temporal del valor
anterior. Por eso muchos programadores prefieren usar ++x por defecto.
Operadores de comparación
Los operadores de comparación devuelven un valor bool: true
o false:
int a = 10;
int b = 20;
bool igual = (a == b); // false
bool diferente = (a != b); // true
bool menor = (a < b); // true
bool mayor = (a > b); // false
bool menorIgual = (a <= b); // true
bool mayorIgual = (a >= b); // false
// Útil en condicionales
if (a < b) {
std::cout << "a es menor que b" << std::endl;
} = es asignación, == es comparación.
if (x = 5) asigna 5 a x y siempre es true (porque 5 != 0).
if (x == 5) compara x con 5.
Este error es tan común que muchos compiladores modernos te dan un warning si
escribes if (x = 5).
Operadores lógicos
Los operadores lógicos te permiten combinar expresiones booleanas:
bool a = true;
bool b = false;
bool and_result = a && b; // false (AND: ambos deben ser true)
bool or_result = a || b; // true (OR: al menos uno debe ser true)
bool not_result = !a; // false (NOT: invierte el valor)
// Cortocircuito: && y || no evalúan el segundo operando si no es necesario
int x = 5;
if (x > 0 && x < 10) { // Si x > 0 es false, no evalúa x < 10
std::cout << "x está entre 0 y 10" << std::endl;
} Evaluación en cortocircuito
Los operadores && y || usan evaluación en cortocircuito :
false && cualquier_cosa→ no evalúacualquier_cosaporque ya esfalsetrue || cualquier_cosa→ no evalúacualquier_cosaporque ya estrue
Esto es útil para evitar errores:
if (ptr != nullptr && ptr->value > 0) {
// Seguro: solo evalúa ptr->value si ptr no es null
} Operadores de asignación compuesta
Son atajos para operaciones comunes:
int x = 10;
x += 5; // x = x + 5; → x = 15
x -= 3; // x = x - 3; → x = 12
x *= 2; // x = x * 2; → x = 24
x /= 4; // x = x / 4; → x = 6
x %= 4; // x = x % 4; → x = 2
// También existen para operadores bit a bit
int y = 8;
y &= 3; // y = y & 3;
y |= 2; // y = y | 2;
y ^= 1; // y = y ^ 1; Operadores bit a bit
Operan directamente sobre los bits individuales de los números. Son esenciales para programación de bajo nivel, flags, máscaras de bits, y optimizaciones:
int a = 12; // 1100 en binario
int b = 10; // 1010 en binario
int and_bit = a & b; // 1000 = 8 (AND bit a bit)
int or_bit = a | b; // 1110 = 14 (OR bit a bit)
int xor_bit = a ^ b; // 0110 = 6 (XOR bit a bit)
int not_bit = ~a; // Invierte todos los bits
// Desplazamiento de bits
int left = a << 2; // 110000 = 48 (multiplica por 4)
int right = a >> 1; // 110 = 6 (divide por 2)
std::cout << "12 << 2 = " << left << std::endl; // 48 Usos comunes de operadores bit a bit Avanzado
- Flags:
flags |= READABLEactiva un flag,flags &= ~READABLElo desactiva - Máscaras: Extraer bits específicos de un valor
- Optimización:
x << 1es más rápido quex * 2(aunque los compiladores modernos optimizan esto) - Gráficos y compresión: Manipular píxeles, codificar/decodificar datos
Operador ternario
El operador ternario ? : es un if-else compacto para asignaciones:
int a = 10;
int b = 20;
// Operador ternario: condicion ? valor_si_true : valor_si_false
int max = (a > b) ? a : b; // max = 20
// Equivalente a:
int max2;
if (a > b) {
max2 = a;
} else {
max2 = b;
}
// Útil para asignaciones condicionales simples
std::string mensaje = (edad >= 18) ? "Adulto" : "Menor";
Úsalo para asignaciones condicionales simples que quepan en una línea.
Si la condición es compleja o las expresiones son largas, usa un if-else
normal para mejor legibilidad.
Precedencia de operadores
Al igual que en matemáticas, los operadores tienen un orden de evaluación:
// Sin paréntesis: sigue precedencia de operadores
int resultado1 = 2 + 3 * 4; // 14 (no 20, porque * tiene mayor precedencia)
int resultado2 = 10 - 4 / 2; // 8 (no 3)
// Con paréntesis: controlas el orden
int resultado3 = (2 + 3) * 4; // 20
int resultado4 = (10 - 4) / 2; // 3
// Múltiples niveles
int resultado5 = ((5 + 3) * 2 - 4) / 2; // 6 Orden de precedencia (de mayor a menor):
- Paréntesis
() - Incremento/decremento
++--, negación! - Multiplicación, división, módulo
*/% - Suma, resta
+- - Desplazamiento
<<>> - Comparación
<<=>>= - Igualdad
==!= - AND bit a bit
& - XOR bit a bit
^ - OR bit a bit
| - AND lógico
&& - OR lógico
|| - Ternario
? : - Asignación
=+=-=etc.
Cuando tengas duda sobre precedencia, usa paréntesis. Es mejor código explícito y legible que código "clever" que requiere memorizar la tabla de precedencia completa.
Resumen
- División entera trunca:
10 / 3 = 3 ++xincrementa antes,x++incrementa después=asigna,==compara&&y||usan evaluación en cortocircuito- Operadores bit a bit manipulan bits individuales
- Usa paréntesis cuando tengas duda sobre precedencia