Ir para o conteúdo

Última atualização:2026-10-12

Tipos de enumeração (enum) em C++

Sobre o autor:

Conta oficial do WeChat:

wechat

Comportamento tradicional

As enumerações têm os seguintes problemas:

  • O escopo é ilimitado, o que facilita conflitos de nomenclatura. Por exemplo, o código a seguir não compila:

enum Color
{
    RED,
    BLUE
};
enum Feeling
{
    EXCITED,
    BLUE
};

int main()
{
    Color a = BLUE; // error
    Feeling b = EXCITED;
    std::cout << a << ":" << b << std::endl;
    return 0;
}
- Conversão implícita para int - O tipo real usado para representar a variável de enumeração não pode ser especificado explicitamente, o que impede a declaração antecipada de tipos de enumeração.

A implementação concreta está em: tradition_color.cpp

Prática clássica

Uma forma simples de resolver os conflitos de nomenclatura causados pelo escopo ilimitado é adicionar um prefixo ao nomear as variáveis de enumeração, como no exemplo acima, alterando para COLOR_BLUE e FEELING_BLUE.

Em geral, por consistência, adicionamos o prefixo a todas as constantes. Mas, assim, o código que define as variáveis de enumeração fica prolixo. Em programas C, talvez seja inevitável fazer assim; programadores C++, porém, dificilmente apreciam esse método. A alternativa são os namespaces:

namespace Color 
{
    enum Type
    {
        RED=15,
        YELLOW,
        BLUE
    };
};

Depois disso, é possível definir uma nova variável de enumeração com Color::Type c = Color::RED;. Se for usado using namespace Color, o prefixo pode até ser omitido, simplificando o código. No entanto, como um namespace pode ser estendido posteriormente com novos conteúdos, o fechamento de escopo que ele oferece não é alto. Em projetos grandes, ainda é possível que pessoas diferentes dêem o mesmo nome de tipo de enumeração a coisas diferentes.

A forma mais "eficaz" é usar uma classe ou estrutura para restringir o escopo: por exemplo, o método para definir novas variáveis é o mesmo do namespace acima; a diferença é que assim não precisamos nos preocupar com a classe sendo modificada em outro lugar. Usa-se uma estrutura, e não uma classe, porque justamente se espera que essas constantes sejam publicamente acessíveis.

struct Color1
{
    enum Type
    {
        RED=102,
        YELLOW,
        BLUE
    };
};

A implementação concreta está em: classic_practice.cpp

As enum classes do C++11

A abordagem acima resolve o primeiro problema, mas continua impotente diante dos outros dois. Felizmente, o padrão C++11 introduziu as "enum classes" (enum class), que resolvem bem os problemas mencionados.

  • O escopo do novo enum deixa de ser global
  • Não há conversão implícita para outros tipos
/**
 * @brief C++11的枚举类
 * 下面等价于enum class Color2:int
 */
enum class Color2
{
    RED=2,
    YELLOW,
    BLUE
};
Color2 c2 = Color2::RED;
cout << static_cast<int>(c2) << endl; //必须转!
  • É possível especificar um tipo específico para armazenar o enum
enum class Color3:char;  // 前向声明

// 定义
enum class Color3:char 
{
    RED='r',
    BLUE
};
char c3 = static_cast<char>(Color3::RED);

A implementação concreta está em: classic_practice.cpp

Tipos de enumeração dentro de classes

Às vezes queremos que certas constantes sejam válidas apenas dentro da classe. Como as constantes de macro definidas por #define são globais e não atendem ao objetivo, pensamos em usar const para modificar membros de dados. De fato, os membros de dados const existem, mas seu significado não é o que esperamos.

Um membro de dados const é constante apenas durante o tempo de vida de um objeto; para a classe inteira, ele é variável, porque a classe pode criar vários objetos, e o valor do membro de dados const pode ser diferente em objetos diferentes.

Não é possível inicializar um membro de dados const na declaração da classe. O uso a seguir está errado, porque, enquanto o objeto da classe não for criado, o compilador não sabe qual é o valor de SIZE. (antes do padrão C++11)

class A 
{
  const int SIZE = 100;   // 错误,企图在类声明中初始化 const 数据成员 
  int array[SIZE];  // 错误,未知的 SIZE 
}; 

O correto é fazê-lo na lista de inicialização do construtor da classe:

class A 
{
  A(int size);  // 构造函数 
  const int SIZE ;    
}; 
A::A(int size) : SIZE(size)  // 构造函数的定义
{ 

} 
A  a(100); // 对象 a 的 SIZE 值为 100 
A  b(200); // 对象 b 的 SIZE 值为 200 

Como estabelecer, então, uma constante fixa em toda a classe?

Não conte com membros de dados const; use constantes de enumeração dentro da classe. Por exemplo:

class Person{
public:
    typedef enum {
        BOY = 0,
        GIRL
    }SexType;
};
//访问的时候通过,Person::BOY或者Person::GIRL来进行访问。

As constantes de enumeração não ocupam espaço de armazenamento dos objetos; elas são todas avaliadas em tempo de compilação.

A desvantagem das constantes de enumeração é que seu tipo de dados implícito é o inteiro, com valor máximo limitado e sem capacidade de representar números de ponto flutuante.

Tópicos relacionados

Comentários