Enum Classes y tipado fuerte
Parte de la sección Programación Orientada a Objetos del Journey de C++ de Coddy — lección 80 de 104.
C++11 introdujo enum classes (también llamadas enumeraciones con ámbito) para abordar las deficiencias de los enums tradicionales al estilo C. Proporcionan una seguridad de tipos más sólida y evitan el uso indebido accidental de los valores de enumeración.
Los enums tradicionales tienen problemas: sus valores se filtran al ámbito circundante y se convierten implícitamente en enteros, lo que provoca errores sutiles:
// Enum tradicional - problemático
enum Color { Red, Green, Blue };
enum TrafficLight { Red, Yellow, Green }; // ¡Error! Red y Green ya están definidos
int x = Red; // Se convierte implícitamente a int (0)
if (Red == 0) { } // Compila - comparando enum con intLas clases Enum resuelven estos problemas al delimitar el alcance de los valores y evitar conversiones implícitas:
enum class Color { Red, Green, Blue };
enum class TrafficLight { Red, Yellow, Green }; // OK - sin conflicto
Color c = Color::Red; // Debe usar el operador de alcance
// int x = c; // ¡Error! Sin conversión implícita
int x = static_cast<int>(c); // Se requiere conversión explícita
// if (c == 0) { } // ¡Error! No se puede comparar con int
if (c == Color::Red) { } // OK - comparando los mismos tiposTambién puedes especificar el tipo subyacente para el control de memoria:
enum class Status : uint8_t {
Inactive = 0,
Active = 1,
Pending = 2
};Las clases Enum se integran bien con los diseños de POO, lo que hace que el código sea más legible y permite detectar errores de tipo en tiempo de compilación en lugar de en tiempo de ejecución.
Desafío
FácilVamos a construir un sistema de prioridad de tareas que utiliza enum classes para representar diferentes niveles de prioridad y estados de tareas. Esto demuestra cómo las enum classes proporcionan seguridad de tipos y previenen los tipos de errores que ocurren con los enums tradicionales.
Organizarás tu código en tres archivos:
TaskTypes.h: Define tus enum classes para el sistema de tareas.Crea una enum class
Prioritycon los valores:Low,Medium,HighyCritical. Especificaintcomo el tipo subyacente, con los valores 1, 2, 3 y 4 respectivamente.Crea una enum class
Statuscon los valores:Pending,InProgressyCompleted.Proporciona dos funciones auxiliares:
priorityToString(Priority p)— devuelve la prioridad como un string ("Low", "Medium", "High" o "Critical")statusToString(Status s)— devuelve el estado como un string ("Pending", "InProgress" o "Completed")
Task.h: Define una claseTaskque utilice tus enum classes.Tu
Taskdebe almacenar un nombre (string), unaPriorityy unStatus. El constructor debe recibir un nombre y una prioridad, con el estado por defecto enStatus::Pending.Implementa estos métodos:
setStatus(Status s)— actualiza el estado de la tareagetPriorityValue()— devuelve el valor entero subyacente de la prioridad utilizandostatic_castdisplay()— imprime la tarea en el formato:[name] - Priority: [priority] (Value: [value]) - Status: [status]
main.cpp: Lee tres entradas:- Nombre de la tarea (string)
- Nivel de prioridad como entero (1=Low, 2=Medium, 3=High, 4=Critical)
- Estado como entero (0=Pending, 1=InProgress, 2=Completed)
Crea una
Taskcon el nombre y la prioridad dados (convierte el entero al valor de enumPriorityapropiado usandostatic_cast). Luego, establece su estado basándote en la tercera entrada. Finalmente, llama adisplay()para mostrar los detalles de la tarea.
Por ejemplo, con las entradas Fix bug, 3 y 1:
Fix bug - Priority: High (Value: 3) - Status: InProgressCon las entradas Write docs, 1 y 2:
Write docs - Priority: Low (Value: 1) - Status: CompletedCon las entradas Deploy app, 4 y 0:
Deploy app - Priority: Critical (Value: 4) - Status: PendingObserva cómo las enum classes mantienen los valores de prioridad y estado completamente separados; no puedes comparar accidentalmente una Priority con un Status ni asignar uno al otro. El static_cast explícito requerido para convertir entre enteros y valores de enum hace que la intención del código sea clara y evita errores sutiles.
Pruébalo tú mismo
#include <iostream>
#include <string>
#include "Task.h"
using namespace std;
int main() {
// Leer entradas
string taskName;
int priorityInt;
int statusInt;
getline(cin, taskName);
cin >> priorityInt;
cin >> statusInt;
// TODO: Crear una Task con el nombre y la prioridad dados
// Usar static_cast para convertir priorityInt al enum Priority
// TODO: Establecer el estado de la tarea basado en statusInt
// Usar static_cast para convertir statusInt al enum Status
// TODO: Llamar a display() para mostrar los detalles de la tarea
return 0;
}Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de OOP
Archivos externosConstrucción y compilación en C++Archivos de cabecera y archivos fuenteNamespaces y alcanceIntroducción a OOP en C++Clases vs ObjetosEl puntero 'this'Métodos (Funciones miembro)Atributos (Miembros de datos)Conceptos básicos de Ctors y DtorsResumen - Calculadora simple4Propiedades de clase
Miembros de instancia vs. estáticosGetters y SettersFunciones miembro constPalabra clave mutableMétodos y variables estáticosFunciones y clases amigasResumen - Gestor de cuentas bancarias7Herencia
Herencia básicaNiveles de acceso en la herenciaOrden de llamada de Ctor y DtorSobrescritura de métodosFunciones virtuales y VTableHerencia múltipleHerencia virtualResumen - Jerarquía de empleados2Gestión de memoria
Memoria Stack vs HeapPunteros y referenciasMemoria dinámica (new/delete)Punteros inteligentes en C++RAII en C++Resumen - Gestor de arrays dinámicos5Encapsulamiento
Especificadores de acceso en C++Especificadores de acceso en profundidadOcultamiento de informaciónStruct vs ClassClases anidadas e internasResumen - Sistema de registros de estudiantes8Polimorfismo
Polimorfismo: Compilación vs. Tiempo de ejecuciónSobrecarga de funcionesFunciones virtuales revisadasFunciones virtuales purasClases abstractasDiseño de interfaces en C++Dynamic Casting y RTTIResumen: Calculadora de figuras11Conceptos avanzados de POO
Composición vs. HerenciaMixins mediante CRTPIdioma PimplBorrado de tiposEnum Classes y tipado fuerteManejo de excepciones en POOJerarquías de excepciones personalizadas14Patrones de diseño - Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositeRAII como patrón3Constructores y Destructores
Constructor por defectoConstructor parametrizadoConstructor de copiaConstructor de movimientoListas de inicialización del constructorConstructores delegadosAnálisis profundo del destructorRegla de tres / cinco / ceroResumen - Clase String6Sobrecarga de operadores
Introducción a la sobrecarga de operadoresSobrecarga de operadores aritméticosSobrecarga de operadores de comparaciónOperadores de flujo (Stream)Sobrecarga del operador de asignaciónSobrecarga de los operadores [] y ()Operadores de conversión de tiposResumen - Clase Matrix9Plantillas
Plantillas de funcionesPlantillas de clasesEspecialización de plantillasPlantillas variádicasConceptos básicos de SFINAE y Type TraitsResumen - Contenedor genérico