Menu
Coddy logo textTech

Enum Classes & Typage fort

Fait partie de la section Programmation Orientée Objet du Journey C++ de Coddy — leçon 80 sur 104.

Le C++11 a introduit les enum classes (également appelées énumérations à portée limitée) pour remédier aux lacunes des énumérations traditionnelles de style C. Elles offrent une sécurité de type plus forte et empêchent l'utilisation abusive accidentelle des valeurs d'énumération.

Les enums traditionnels posent des problèmes : leurs valeurs s'échappent dans la portée environnante et se convertissent implicitement en entiers, ce qui entraîne des bugs subtils :

// Enum traditionnel - problématique
enum Color { Red, Green, Blue };
enum TrafficLight { Red, Yellow, Green };  // Erreur ! Red et Green sont déjà définis

int x = Red;  // Se convertit implicitement en int (0)
if (Red == 0) { }  // Compile - comparaison d'un enum avec un int

Les classes d'énumération (enum classes) résolvent ces problèmes en limitant la portée des valeurs et en empêchant les conversions implicites :

enum class Color { Red, Green, Blue };
enum class TrafficLight { Red, Yellow, Green };  // OK - pas de conflit

Color c = Color::Red;      // Doit utiliser l'opérateur de portée
// int x = c;              // Erreur ! Pas de conversion implicite
int x = static_cast<int>(c);  // Conversion explicite requise

// if (c == 0) { }         // Erreur ! Impossible de comparer à un int
if (c == Color::Red) { }   // OK - comparaison de types identiques

Vous pouvez également spécifier le type sous-jacent pour le contrôle de la mémoire :

enum class Status : uint8_t {
    Inactive = 0,
    Active = 1,
    Pending = 2
};

Les classes Enum s'intègrent bien aux conceptions POO, rendant le code plus lisible et permettant de détecter les erreurs de type au moment de la compilation plutôt qu'à l'exécution.

challenge icon

Défi

Facile

Construisons un système de priorité de tâches qui utilise des classes enum pour représenter différents niveaux de priorité et statuts de tâches. Cela démontre comment les classes enum assurent la sécurité des types et préviennent les types de bogues qui surviennent avec les enums traditionnels.

Vous organiserez votre code sur trois fichiers :

  • TaskTypes.h : Définissez vos classes enum pour le système de tâches.

    Créez une classe enum Priority avec les valeurs : Low, Medium, High, et Critical. Spécifiez int comme type sous-jacent, avec les valeurs 1, 2, 3, et 4 respectivement.

    Créez une classe enum Status avec les valeurs : Pending, InProgress, et Completed.

    Fournissez deux fonctions d'aide :

    • priorityToString(Priority p) — retourne la priorité sous forme de chaîne de caractères ("Low", "Medium", "High", ou "Critical")
    • statusToString(Status s) — retourne le statut sous forme de chaîne de caractères ("Pending", "InProgress", ou "Completed")
  • Task.h : Définissez une classe Task qui utilise vos classes enum.

    Votre Task doit stocker un nom (string), une Priority, et un Status. Le constructeur doit prendre un nom et une priorité, le statut étant par défaut Status::Pending.

    Implémentez ces méthodes :

    • setStatus(Status s) — met à jour le statut de la tâche
    • getPriorityValue() — retourne la valeur entière sous-jacente de la priorité en utilisant static_cast
    • display() — affiche la tâche au format : [name] - Priority: [priority] (Value: [value]) - Status: [status]
  • main.cpp : Lisez trois entrées :
    1. Nom de la tâche (string)
    2. Niveau de priorité sous forme d'entier (1=Low, 2=Medium, 3=High, 4=Critical)
    3. Statut sous forme d'entier (0=Pending, 1=InProgress, 2=Completed)

    Créez une Task avec le nom et la priorité donnés (convertissez l'entier en la valeur enum Priority appropriée en utilisant static_cast). Ensuite, définissez son statut en fonction de la troisième entrée. Enfin, appelez display() pour afficher les détails de la tâche.

Par exemple, avec les entrées Fix bug, 3, et 1 :

Fix bug - Priority: High (Value: 3) - Status: InProgress

Avec les entrées Write docs, 1, et 2 :

Write docs - Priority: Low (Value: 1) - Status: Completed

Avec les entrées Deploy app, 4, et 0 :

Deploy app - Priority: Critical (Value: 4) - Status: Pending

Remarquez comment les classes enum maintiennent les valeurs de priorité et de statut complètement séparées — vous ne pouvez pas comparer accidentellement une Priority à un Status ou assigner l'un à l'autre. Le static_cast explicite requis pour convertir entre les entiers et les valeurs enum rend l'intention du code claire et prévient les bogues subtils.

Aide-mémoire

Le C++11 a introduit les enum classes (énumérations à portée limitée) pour offrir une sécurité de type plus forte que les énumérations traditionnelles de style C.

Les énumérations traditionnelles posent des problèmes de fuite de portée et de conversions implicites :

// Énumération traditionnelle - problématique
enum Color { Red, Green, Blue };
enum TrafficLight { Red, Yellow, Green };  // Erreur ! Red et Green sont déjà définis

int x = Red;  // Conversion implicite en int
if (Red == 0) { }  // Compile - comparaison d'une énumération avec un int

Les enum classes résolvent ces problèmes en exigeant la résolution de portée et en empêchant les conversions implicites :

enum class Color { Red, Green, Blue };
enum class TrafficLight { Red, Yellow, Green };  // OK - pas de conflit

Color c = Color::Red;      // Doit utiliser l'opérateur de portée
// int x = c;              // Erreur ! Pas de conversion implicite
int x = static_cast<int>(c);  // Conversion explicite requise

// if (c == 0) { }         // Erreur ! Impossible de comparer avec un int
if (c == Color::Red) { }   // OK - comparaison de types identiques

Vous pouvez spécifier le type sous-jacent pour le contrôle de la mémoire :

enum class Status : uint8_t {
    Inactive = 0,
    Active = 1,
    Pending = 2
};

Pour convertir entre les enum classes et les entiers, utilisez un transtypage (cast) explicite :

// De l'entier vers l'enum class
Priority p = static_cast<Priority>(3);

// De l'enum class vers l'entier
int value = static_cast<int>(p);

Essayez vous-même

#include <iostream>
#include <string>
#include "Task.h"

using namespace std;

int main() {
    // Lire les entrées
    string taskName;
    int priorityInt;
    int statusInt;
    
    getline(cin, taskName);
    cin >> priorityInt;
    cin >> statusInt;
    
    // TODO: Créer une Task avec le nom et la priorité donnés
    // Utiliser static_cast pour convertir priorityInt en énumération Priority
    
    // TODO: Définir le statut de la tâche en fonction de statusInt
    // Utiliser static_cast pour convertir statusInt en énumération Status
    
    // TODO: Appeler display() pour afficher les détails de la tâche
    
    return 0;
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation Orientée Objet