Enum no C++

enum c++

No C++ deve-se tomar um pouco de cuidado quando se utiliza enums principalmente no que se refere ao tipo pois para efeito de comparação eles são considerados como inteiros e não como um novo tipo. Por exemplo:

int main() {
    enum Color {
        RED, // o compilador interpreta como inteiro 0
        BLUE // o compilador interpreta como inteiro 1
    };
 
    enum Fruit {
        BANANA, // o compilador também interpreta como inteiro 0
        APPLE // o compilador também interpreta como inteiro 1
    };
	
    Color color = RED;
    Fruit fruit = BANANA;
 
    if (color == fruit) // fazendo comparação de inteiros
        std::cout << "enums são iguais\n";
    else
        std::cout << "enums são diferentes\n";
 
    return 0;
}

Quando o C++ compara Color e Fruit, ele converte implicitamente ambos os “enums” em inteiros e portanto compara os inteiros. Como Color e Fruit foram definidos como enumeradores que avaliam o valor 0, isso significa que, no exemplo acima, a cor será igual a fruta. Isto definitivamente não é tão desejado, já que a cor e a fruta são de diferentes enumerações e não se destinam a ser comparáveis!

O C++ 11 definiu um novo conceito, onde a classe enum (também chamada de enumeração com escopo definido), que torna as enumerações fortemente tipificadas e escopadas. Para criar uma classe enum, usa-se a palavra-chave “class” após a palavra-chave “enum”. Veja um exemplo:

int main() {
    enum class Color {
        RED,
        BLUE
    };
 
    enum class Fruit {
        BANANA,
        APPLE
    };
 
    Color color = Color::RED;
    Fruit fruit = Fruit::BANANA;
	
    if (color == fruit) // erro de compilação pois são classes diferentes
        std::cout << "enums são iguais\n";
    else
        std::cout << "enums são diferentes\n";
 
    return 0;
}

Com as enumerações normais, os enumeradores são colocados no mesmo escopo da própria enumeração, portanto, é possível acessar os enumeradores diretamente (por exemplo, RED). No entanto, com classes enum, as regras de escopo forte significam que todos os enumeradores são considerados parte da enumeração, portanto, será preciso usar um qualificador de escopo para acessar o enumerador (por exemplo, Color::RED).

As regras de digitação fortes significam que cada classe enum é considerada um tipo exclusivo. Isso significa que o compilador não irá implicitamente comparar enumeradores de enumerações diferentes. Se for tentado fazer isso, o compilador lançará um erro, conforme mostrado no exemplo acima.

No entanto, ainda pode-se comparar enumeradores de dentro da mesma classe enum (desde que eles sejam do mesmo tipo):

int main() {
    enum class Color {
        GREEN,
        YELLOW
    };
 
    Color color = Color::GREEN;
 
    if (color == Color::GREEN)
        std::cout << "Verde!\n";
    else if (color == Color::YELLOW)
        std::cout << "Amarelo!\n";
 
    return 0;
}

Com as classes enum, o compilador não converterá mais implicitamente os valores do enumerador em números inteiros. Isso é uma coisa boa. No entanto, ocasionalmente há casos em que é útil poder fazê-lo. Nesses casos, deve-se converter explicitamente um enumerador de classe enum para um inteiro usando um static_cast para int:

int main() {
    enum class Color {
        GREEN,
        YELLOW
    };
 
    Color color = Color::YELLOW;
 
    std::cout << color; // erro
    std::cout << static_cast<int>(color); // imprime 1
 
    return 0;
}

Conclusão

Se for utilizado um compilador C++ 11 ou posterior, há poucas razões para usar tipos enumerados normais em vez de classes enum.

A palavra-chave class, juntamente com a palavra-chave static, forma uma das palavras-chave mais sobrecarregadas na linguagem C++ e pode ter diferentes significados dependendo do contexto. Embora as classes enum usem a palavra-chave class, elas não são consideradas “classes” no sentido tradicional do C++.

Além disso, “enum struct” é equivalente a “enum class”. Mas esse uso não é recomendado e não é comumente usado.