Enum Classes e Tipagem Forte
Parte da seção Programação Orientada a Objetos do Journey de C++ da Coddy — lição 80 de 104.
O C++11 introduziu enum classes (também chamadas de enumerações com escopo) para resolver as deficiências dos enums tradicionais no estilo C. Elas fornecem uma segurança de tipo mais forte e evitam o uso indevido acidental de valores de enumeração.
Enums tradicionais têm problemas: seus valores vazam para o escopo circundante e se convertem implicitamente em inteiros, levando a bugs sutis:
// Enum tradicional - problemático
enum Color { Red, Green, Blue };
enum TrafficLight { Red, Yellow, Green }; // Erro! Red e Green já definidos
int x = Red; // Converte implicitamente para int (0)
if (Red == 0) { } // Compila - comparando enum com intAs classes Enum resolvem esses problemas ao definir o escopo dos valores e impedir conversões implícitas:
enum class Color { Red, Green, Blue };
enum class TrafficLight { Red, Yellow, Green }; // OK - sem conflito
Color c = Color::Red; // Deve usar o operador de escopo
// int x = c; // Erro! Sem conversão implícita
int x = static_cast<int>(c); // Conversão explícita necessária
// if (c == 0) { } // Erro! Não é possível comparar com int
if (c == Color::Red) { } // OK - comparando os mesmos tiposVocê também pode especificar o tipo subjacente para controle de memória:
enum class Status : uint8_t {
Inactive = 0,
Active = 1,
Pending = 2
};Classes Enum integram-se bem com designs de POO, tornando o código mais legível e capturando erros de tipo em tempo de compilação em vez de tempo de execução.
Desafio
FácilVamos construir um sistema de prioridade de tarefas que utiliza enum classes para representar diferentes níveis de prioridade e status de tarefas. Isso demonstra como as enum classes fornecem segurança de tipo e evitam os tipos de bugs que ocorrem com enums tradicionais.
Você organizará seu código em três arquivos:
TaskTypes.h: Defina suas enum classes para o sistema de tarefas.Crie uma enum class
Prioritycom os valores:Low,Medium,HigheCritical. Especifiqueintcomo o tipo subjacente, com os valores 1, 2, 3 e 4, respectivamente.Crie uma enum class
Statuscom os valores:Pending,InProgresseCompleted.Forneça duas funções auxiliares:
priorityToString(Priority p)— retorna a prioridade como uma string ("Low", "Medium", "High" ou "Critical")statusToString(Status s)— retorna o status como uma string ("Pending", "InProgress" ou "Completed")
Task.h: Defina uma classeTaskque utiliza suas enum classes.Sua
Taskdeve armazenar um nome (string), umaPrioritye umStatus. O construtor deve receber um nome e uma prioridade, com o status padrão sendoStatus::Pending.Implemente estes métodos:
setStatus(Status s)— atualiza o status da tarefagetPriorityValue()— retorna o valor inteiro subjacente da prioridade usandostatic_castdisplay()— imprime a tarefa no formato:[name] - Priority: [priority] (Value: [value]) - Status: [status]
main.cpp: Leia três entradas:- Nome da tarefa (string)
- Nível de prioridade como inteiro (1=Low, 2=Medium, 3=High, 4=Critical)
- Status como inteiro (0=Pending, 1=InProgress, 2=Completed)
Crie uma
Taskcom o nome e a prioridade fornecidos (converta o inteiro para o valor de enumPriorityapropriado usandostatic_cast). Em seguida, defina seu status com base na terceira entrada. Por fim, chamedisplay()para mostrar os detalhes da tarefa.
Por exemplo, com as entradas Fix bug, 3 e 1:
Fix bug - Priority: High (Value: 3) - Status: InProgressCom as entradas Write docs, 1 e 2:
Write docs - Priority: Low (Value: 1) - Status: CompletedCom as entradas Deploy app, 4 e 0:
Deploy app - Priority: Critical (Value: 4) - Status: PendingObserve como as enum classes mantêm os valores de prioridade e status completamente separados — você não pode comparar acidentalmente uma Priority com um Status ou atribuir um ao outro. O static_cast explícito necessário para converter entre inteiros e valores de enum torna a intenção do código clara e evita bugs sutis.
Folha de consulta
O C++11 introduziu enum classes (enumerações com escopo) para fornecer uma segurança de tipo mais forte do que os enums tradicionais do estilo C.
Enums tradicionais têm problemas com vazamento de escopo e conversões implícitas:
// Traditional enum - problematic
enum Color { Red, Green, Blue };
enum TrafficLight { Red, Yellow, Green }; // Erro! Red e Green já definidos
int x = Red; // Converte implicitamente para int
if (Red == 0) { } // Compila - comparando enum com intEnum classes resolvem esses problemas exigindo resolução de escopo e impedindo conversões implícitas:
enum class Color { Red, Green, Blue };
enum class TrafficLight { Red, Yellow, Green }; // OK - sem conflito
Color c = Color::Red; // Deve usar o operador de escopo
// int x = c; // Erro! Sem conversão implícita
int x = static_cast<int>(c); // Conversão explícita necessária
// if (c == 0) { } // Erro! Não é possível comparar com int
if (c == Color::Red) { } // OK - comparando os mesmos tiposVocê pode especificar o tipo subjacente para controle de memória:
enum class Status : uint8_t {
Inactive = 0,
Active = 1,
Pending = 2
};Para converter entre enum classes e inteiros, use casting explícito:
// Inteiro para enum class
Priority p = static_cast<Priority>(3);
// Enum class para inteiro
int value = static_cast<int>(p);Experimente você mesmo
#include <iostream>
#include <string>
#include "Task.h"
using namespace std;
int main() {
// Ler as entradas
string taskName;
int priorityInt;
int statusInt;
getline(cin, taskName);
cin >> priorityInt;
cin >> statusInt;
// TODO: Criar uma Task com o nome e prioridade fornecidos
// Use static_cast para converter priorityInt para o enum Priority
// TODO: Definir o status da tarefa com base em statusInt
// Use static_cast para converter statusInt para o enum Status
// TODO: Chamar display() para mostrar os detalhes da tarefa
return 0;
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de OOP
Arquivos ExternosBuild e Compilação em C++Arquivos Header e SourceNamespaces e EscopoIntrodução a OOP em C++Classes vs ObjetosO Ponteiro 'this'Métodos (Funções Membro)Atributos (Membros de Dados)Básico de Ctors e DtorsRecapitulação - Calculadora Simples4Propriedades de Classe
Membros de Instância vs EstáticosGetters e SettersFunções de Membro ConstPalavra-chave MutableMétodos e Variáveis EstáticosFunções e Classes FriendRecapitulação - Gerenciador de Conta Bancária7Herança
Herança BásicaNíveis de Acesso na HerançaOrdem de Chamada de Ctor e DtorSobrescrita de MétodosFunções Virtuais e VTableHerança MúltiplaHerança VirtualRecapitulação - Hierarquia de Funcionários2Gerenciamento de Memória
Memória Stack vs HeapPonteiros e ReferênciasMemória Dinâmica (new/delete)Smart Pointers em C++RAII em C++Recapitulação - Gerenciador de Array Dinâmico5Encapsulamento
Especificadores de Acesso em C++Especificadores de Acesso em DetalhesOcultação de InformaçãoStruct vs ClassClasses Aninhadas e InternasRecapitulação - Sistema de Registros de Alunos8Polimorfismo
Polimorfismo de Compilação vs Tempo de ExecuçãoSobrecarga de FunçõesFunções Virtuais RevisitadasFunções Virtuais PurasClasses AbstratasDesign de Interfaces em C++Dynamic Casting e RTTIRecapitulação - Calculadora de Formas11Conceitos Avançados de POO
Composição vs HerançaMixins via CRTPPimpl IdiomType ErasureEnum Classes e Tipagem ForteTratamento de Exceções em POOHierarquias de Exceções Personalizadas3Construtores e Destrutores
Construtor PadrãoConstrutor ParametrizadoConstrutor de CópiaConstrutor de MovimentaçãoListas de Inicialização do ConstrutorConstrutores DelegadosMergulho Profundo em DestrutoresRegra dos Três / Cinco / ZeroRecapitulação - Classe String6Sobrecarga de Operadores
Introdução à Sobrecarga de OperadoresSobrecarga de Operadores AritméticosSobrecarga de Operadores de ComparaçãoOperadores de StreamSobrecarga do Operador de AtribuiçãoSobrecarga dos Operadores [] e ()Operadores de Conversão de TipoRecapitulação - Classe Matrix9Templates
Templates de FunçãoTemplates de ClasseEspecialização de TemplatesTemplates VariádicosFundamentos de SFINAE e Type TraitsRecapitulação - Container Genérico