Enum class e tipizzazione forte
Fa parte della sezione Programmazione orientata agli oggetti del percorso C++ di Coddy. Lezione 80 di 104.
C++11 ha introdotto le enum class (chiamate anche enumerazioni con ambito) per affrontare i limiti delle tradizionali enumerazioni in stile C. Offrono una maggiore sicurezza dei tipi e impediscono l'uso improprio accidentale dei valori dell'enumerazione.
Gli enum tradizionali presentano dei problemi: i loro valori si riversano nell'ambito circostante e vengono convertiti implicitamente in interi, causando bug difficili da individuare:
// enum tradizionale - problematico
enum Color { Red, Green, Blue };
enum TrafficLight { Red, Yellow, Green }; // Errore! Red e Green sono già definiti
int x = Red; // Si converte implicitamente in int (0)
if (Red == 0) { } // Si compila - confronto tra enum e intLe classi enum risolvono questi problemi definendo l'ambito dei valori e impedendo le conversioni implicite:
enum class Color { Red, Green, Blue };
enum class TrafficLight { Red, Yellow, Green }; // OK - nessun conflitto
Color c = Color::Red; // È necessario usare l'operatore di risoluzione dell'ambito
// int x = c; // Errore! Nessuna conversione implicita
int x = static_cast<int>(c); // È necessaria una conversione esplicita
// if (c == 0) { } // Errore! Non è possibile confrontare con int
if (c == Color::Red) { } // OK - confronto tra tipi ugualiPuoi anche specificare il tipo sottostante per controllare la memoria:
enum class Status : uint8_t {
Inactive = 0,
Active = 1,
Pending = 2
};Le classi enum si integrano bene con le progettazioni OOP, rendono il codice più leggibile e rilevano gli errori di tipo in fase di compilazione anziché a runtime.
Sfida
FacileCostruiamo un sistema di priorità per le attività che usa classi enum per rappresentare i diversi livelli di priorità e gli stati delle attività. Questo dimostra come le classi enum garantiscano la sicurezza dei tipi e prevengano i tipi di bug che si verificano con gli enum tradizionali.
Organizzerai il codice in tre file:
TaskTypes.h: definisci le classi enum per il sistema di attività.Crea una classe enum
Prioritycon i valori:Low,Medium,HigheCritical. Specificaintcome tipo sottostante, con i valori rispettivamente 1, 2, 3 e 4.Crea una classe enum
Statuscon i valori:Pending,InProgresseCompleted.Fornisci due funzioni di supporto:
priorityToString(Priority p): restituisce la priorità come stringa ("Low", "Medium", "High", o "Critical")statusToString(Status s): restituisce lo stato come stringa ("Pending", "InProgress", o "Completed")
Task.h: definisci una classeTaskche utilizza le classi enum.La classe
Taskdeve memorizzare un nome (stringa), unaPrioritye unoStatus. Il costruttore deve accettare un nome e una priorità, mentre lo stato deve avere come valore predefinitoStatus::Pending.Implementa questi metodi:
setStatus(Status s): aggiorna lo stato dell'attivitàgetPriorityValue(): restituisce il valore intero sottostante della priorità usandostatic_castdisplay(): stampa l'attività nel formato:[name] - Priority: [priority] (Value: [value]) - Status: [status]
main.cpp: leggi tre input:- Nome dell'attività (stringa)
- Livello di priorità come intero (1=Low, 2=Medium, 3=High, 4=Critical)
- Stato come intero (0=Pending, 1=InProgress, 2=Completed)
Crea una
Taskcon il nome e la priorità specificati (converti l'intero nel valore enumPriorityappropriato usandostatic_cast). Poi imposta lo stato in base al terzo input. Infine, chiamadisplay()per mostrare i dettagli dell'attività.
Per esempio, con gli input Fix bug, 3 e 1:
Fix bug - Priority: High (Value: 3) - Status: InProgressCon gli input Write docs, 1 e 2:
Write docs - Priority: Low (Value: 1) - Status: CompletedCon gli input Deploy app, 4 e 0:
Deploy app - Priority: Critical (Value: 4) - Status: PendingNota come le classi enum mantengano i valori di priorità e stato completamente separati. Non puoi confrontare accidentalmente una Priority con uno Status né assegnare l'una all'altro. L'uso esplicito di static_cast, necessario per convertire tra interi e valori enum, rende chiaro l'intento del codice e previene bug difficili da individuare.
Provalo tu
#include <iostream>
#include <string>
#include "Task.h"
using namespace std;
int main() {
// Leggi i dati di input
string taskName;
int priorityInt;
int statusInt;
getline(cin, taskName);
cin >> priorityInt;
cin >> statusInt;
// TODO: Crea un Task con il nome e la priorità specificati
// Usa static_cast per convertire priorityInt nell'enum Priority
// TODO: Imposta lo stato dell'attività in base a statusInt
// Usa static_cast per convertire statusInt nell'enum Status
// TODO: Chiama display() per mostrare i dettagli dell'attività
return 0;
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti della programmazione orientata agli oggetti
File esterniBuild e compilazione in C++File header e file sorgenteNamespace e ambitoIntroduzione alla programmazione orientata agli oggetti in C++Classi e oggetti a confrontoIl puntatore 'this'Metodi (funzioni membro)Attributi (membri dati)Fondamenti di costruttori e distruttoriRiepilogo - Calcolatrice semplice4Proprietà delle classi
Membri di istanza e staticiGetter e setterFunzioni membro constParola chiave mutableMetodi e variabili staticiFunzioni e classi friendRiepilogo - Gestore di conti bancari7Ereditarietà
Ereditarietà di baseLivelli di accesso nell’ereditarietàOrdine di chiamata di costruttori e distruttoriRidefinizione dei metodiFunzioni virtuali e VTableEreditarietà multiplaEreditarietà virtualeRiepilogo - Gerarchia dei dipendenti2Gestione della memoria
Memoria Stack vs HeapPuntatori e riferimentiMemoria dinamica (new/delete)Puntatori intelligenti in C++RAII in C++Riepilogo - Gestore di array dinamico5Incapsulamento
Specificatori di accesso in C++Specificatori di accesso in dettaglioOccultamento delle informazioniStruct vs classClassi annidate e interneRiepilogo - Sistema di registrazione degli studenti8Polimorfismo
Polimorfismo a compile time e a runtimeOverload delle funzioniFunzioni virtuali: ripassoFunzioni virtuali pureClassi astratteProgettazione delle interfacce in C++Dynamic casting e RTTIRipasso: calcolatrice di forme11Concetti avanzati di OOP
Composizione vs ereditarietàMixin tramite CRTPIdiom PimplType ErasureEnum class e tipizzazione forteGestione delle eccezioni in OOPGerarchie personalizzate di eccezioni14Pattern di progettazione - Parte 2
Pattern CommandPattern AdapterPattern DecoratorPattern Template MethodPattern StatePattern CompositeRAII come pattern3Costruttori e distruttori
Costruttore predefinitoCostruttore con parametriCostruttore di copiaCostruttore di spostamentoListe di inizializzazione dei costruttoriCostruttori delegantiApprofondimento sui distruttoriRegola del Tre / Cinque / ZeroRipasso - classe String6Sovraccarico degli operatori
Introduzione al sovraccarico degli operatoriSovraccarico degli operatori aritmeticiSovraccarico degli operatori di confrontoOperatori di flussoSovraccarico dell'operatore di assegnazioneSovraccarico degli operatori [] e ()Operatori di conversione di tipoRipasso - Classe Matrix9Template
Template di funzioneTemplate di classeSpecializzazione dei templateTemplate variadiciBasi di SFINAE e dei trait di tipoRiepilogo - Contenitore genericoEsercitati da solo: Compilatore C++ online