Enums com escopo em C++: por que enum class é mais seguro que o enum antigo?

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Por que enum class é seu novo melhor amigo em C++?



Todo mundo que começou a estudar C++ ou voltou a ele após uma pausa, mais cedo ou mais tarde, enfrenta o dilema: usar o bom e velho enum ou seu irmão mais moderno enum class? No Stack Overflow, a pergunta «Why is enum class considered safer to use than plain enum?» acumulou milhares de visualizações — e não é por acaso. A migração para scoped enum (que é o nome oficial do enum class) não é apenas uma questão de moda, mas um passo real em direção a um código mais confiável e legível.



Vamos entender exatamente onde está o perigo do enum antigo e como o enum class ajuda a evitar toda uma classe de erros. Se você programa em C++ e ainda usa enum sem escopo, este artigo é para você.



Top 3 erros do enum antigo (e como enum class os corrige)



1️⃣ Poluição do escopo global



O problema mais comum do enum antigo é que suas constantes "vazam" para o espaço de nomes ao redor. Imagine que você tem duas enumerações:



// Ruim: enum antigoenum Color { Red, Green, Blue };enum Feeling { Happy, Sad, Blue }; // Erro de compilação! Blue já foi definido


A constante Blue de Color já está ocupada, e você não pode usar o mesmo nome em Feeling. Em um projeto grande com centenas de arquivos, isso causa uma verdadeira dor de cabeça. Você precisa inventar nomes longos como Color_Blue ou COLOR_BLUE, o que polui o código.



Solução com enum class:



// Bom: enum class (scoped enum)enum class Color { Red, Green, Blue };enum class Feeling { Happy, Sad, Blue }; // OK! Sem conflito


Agora Blue vive dentro de sua própria classe. Para acessá-lo, você precisa escrever Color::Blue ou Feeling::Blue. Isso não apenas resolve o problema de colisões, mas também torna o código autodocumentado — fica imediatamente claro a qual tipo o valor pertence.



2️⃣ Conversão implícita para int (e vice-versa)



O enum antigo é convertido implicitamente para tipos inteiros. À primeira vista, isso é conveniente, mas na prática é uma fonte de bugs difíceis de detectar.



// Enum antigo perigosoenum WarningLevel { Low, Medium, High };

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

setVolume(High); // Funciona! Mas High = 2, não é um nível de volume// Você acidentalmente passou um nível de alerta em vez do volume — o compilador não reclama


O compilador aceita isso sem um único aviso. E se você trocar a ordem dos argumentos em uma função — o bug vai para o runtime.



Como enum class protege:



enum class WarningLevel { Low, Medium, High };

void setVolume(int level);

setVolume(WarningLevel::High); // Erro de compilação!// Não há conversão implícita de enum class para int


O compilador força você a converter o valor explicitamente, se realmente necessário. Isso significa que você tem consciência de cada conversão, em vez de confiar no "talvez funcione".



// Se for realmente necessário — faça explicitamentesetVolume(static_cast<int>(WarningLevel::High)); // Explícito e claro


3️⃣ Tipo base indefinido



O enum antigo não garante qual tipo inteiro será usado internamente. O compilador escolhe por conta própria (geralmente int), e isso pode causar surpresas ao transferir código entre diferentes compiladores ou plataformas.



// O tamanho pode ser diferente!enum Small { A, B, C }; // Pode ser int, pode ser charenum Big { X = 100000, Y, Z }; // Ainda pode ser int


Com enum class, você pode especificar explicitamente o tipo base, o que dá controle total

Blogs

Book Recommendations