Fundamentos

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

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)
Cuidado con la división entera

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:

¿Por qué 10 % 3 da 1?
Respuesta:

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;
}
Error común: = vs ==

= 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 :

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 |= READABLE activa un flag, flags &= ~READABLE lo desactiva
  • Máscaras: Extraer bits específicos de un valor
  • Optimización: x << 1 es más rápido que x * 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";
Cuándo usar el operador ternario

Ú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):

  1. Paréntesis ()
  2. Incremento/decremento ++ --, negación !
  3. Multiplicación, división, módulo * / %
  4. Suma, resta + -
  5. Desplazamiento << >>
  6. Comparación < <= > >=
  7. Igualdad == !=
  8. AND bit a bit &
  9. XOR bit a bit ^
  10. OR bit a bit |
  11. AND lógico &&
  12. OR lógico ||
  13. Ternario ? :
  14. Asignación = += -= etc.
Consejo profesional

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

Siguiente capítulo: Tipos de Datos →