Enums con ámbito en C++: ¿por qué enum class es más seguro que el antiguo enum?

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

¿Por qué enum class es su nuevo mejor amigo en C++?



Cualquiera que haya empezado a estudiar C++ o haya vuelto a él después de un descanso, tarde o temprano se enfrenta al dilema: usar el clásico enum o su hermano más moderno enum class? En Stack Overflow, la pregunta «Why is enum class considered safer to use than plain enum?» ha acumulado miles de visitas, y no es casualidad. La transición a scoped enum (así se llama oficialmente enum class) no es solo una cuestión de moda, sino un paso real hacia un código más fiable y legible.



Analicemos en qué consiste exactamente el peligro del antiguo enum y cómo enum class ayuda a evitar toda una clase de errores. Si programas en C++ y todavía usas enum sin ámbito de visibilidad, este artículo es para ti.



Top 3 errores del antiguo enum (y cómo los corrige enum class)



1️⃣ Contaminación del ámbito global de visibilidad



El problema más común del antiguo enum es que sus constantes «se salen» al espacio de nombres circundante. Imagina que tienes dos enumeraciones:



// Mal: antiguo enumenum Color { Red, Green, Blue };enum Feeling { Happy, Sad, Blue }; // ¡Error de compilación! Blue ya está definido


La constante Blue de Color ya está ocupada, y no puedes usar el mismo nombre en Feeling. En un proyecto grande con cientos de archivos, esto se convierte en un verdadero dolor de cabeza. Hay que inventar nombres largos como Color_Blue o COLOR_BLUE, lo que afea el código.



Solución con enum class:



// Bien: enum class (scoped enum)enum class Color { Red, Green, Blue };enum class Feeling { Happy, Sad, Blue }; // ¡OK! No hay conflicto


Ahora Blue vive dentro de su propia clase. Para acceder a él, hay que escribir Color::Blue o Feeling::Blue. Esto no solo resuelve el problema de colisiones, sino que también hace que el código sea autodocumentado: se ve inmediatamente a qué tipo pertenece el valor.



2️⃣ Conversión implícita a int (y viceversa)



El antiguo enum se convierte implícitamente a tipos enteros. A primera vista es conveniente, pero en la práctica es una fuente de errores difíciles de detectar.



// Antiguo enum peligrosoenum WarningLevel { Low, Medium, High };

void setVolume(int level) { if (level > 10) level = 10; // ...}

setVolume(High); // ¡Funciona! Pero High = 2, no es un nivel de volumen// Accidentalmente pasaste un nivel de alerta en lugar del volumen — el compilador calla


El compilador aceptará esto sin una sola advertencia. Y si confundes el orden de los argumentos en una función, el error pasará a tiempo de ejecución.



Cómo protege enum class:



enum class WarningLevel { Low, Medium, High };

void setVolume(int level);

setVolume(WarningLevel::High); // ¡Error de compilación!// No hay conversión implícita de enum class a int


El compilador te obligará a convertir explícitamente el valor si realmente es necesario. Esto significa que eres consciente de cada conversión, en lugar de confiar en un «quizás funcione».



// Si es realmente necesario — lo hacemos explícitamentesetVolume(static_cast<int>(WarningLevel::High)); // Explícito y claro


3️⃣ Tipo base no definido



El antiguo enum no garantiza qué tipo entero se usará internamente. El compilador lo elige por sí mismo (normalmente int), y esto puede provocar sorpresas al transferir entre diferentes compiladores o plataformas.



// ¡El tamaño puede ser diferente!enum Small { A, B, C }; // Puede ser int, puede ser charenum Big { X = 100000, Y, Z }; // Sigue pudiendo ser int


Con enum class puedes especificar explícitamente el tipo base, lo que te da control total

Blogs

Book Recommendations