Menu
Coddy logo textTech

Enum Classes & Strong Typing

Part of the Object Oriented Programming section of Coddy's C++ journey — lesson 80 of 104.

C++11 introduced enum classes (also called scoped enumerations) to address the shortcomings of traditional C-style enums. They provide stronger type safety and prevent accidental misuse of enumeration values.

Traditional enums have problems: their values leak into the surrounding scope and implicitly convert to integers, leading to subtle bugs:

// Traditional enum - problematic
enum Color { Red, Green, Blue };
enum TrafficLight { Red, Yellow, Green };  // Error! Red and Green already defined

int x = Red;  // Implicitly converts to int (0)
if (Red == 0) { }  // Compiles - comparing enum to int

Enum classes solve these issues by scoping values and preventing implicit conversions:

enum class Color { Red, Green, Blue };
enum class TrafficLight { Red, Yellow, Green };  // OK - no conflict

Color c = Color::Red;      // Must use scope operator
// int x = c;              // Error! No implicit conversion
int x = static_cast<int>(c);  // Explicit conversion required

// if (c == 0) { }         // Error! Can't compare to int
if (c == Color::Red) { }   // OK - comparing same types

You can also specify the underlying type for memory control:

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

Enum classes integrate well with OOP designs, making code more readable and catching type errors at compile time rather than runtime.

challenge icon

Challenge

Easy

Let's build a task priority system that uses enum classes to represent different priority levels and task statuses. This demonstrates how enum classes provide type safety and prevent the kinds of bugs that occur with traditional enums.

You'll organize your code across three files:

  • TaskTypes.h: Define your enum classes for the task system.

    Create a Priority enum class with values: Low, Medium, High, and Critical. Specify int as the underlying type, with values 1, 2, 3, and 4 respectively.

    Create a Status enum class with values: Pending, InProgress, and Completed.

    Provide two helper functions:

    • priorityToString(Priority p) — returns the priority as a string ("Low", "Medium", "High", or "Critical")
    • statusToString(Status s) — returns the status as a string ("Pending", "InProgress", or "Completed")
  • Task.h: Define a Task class that uses your enum classes.

    Your Task should store a name (string), a Priority, and a Status. The constructor should take a name and priority, with status defaulting to Status::Pending.

    Implement these methods:

    • setStatus(Status s) — updates the task's status
    • getPriorityValue() — returns the underlying integer value of the priority using static_cast
    • display() — prints the task in the format: [name] - Priority: [priority] (Value: [value]) - Status: [status]
  • main.cpp: Read three inputs:
    1. Task name (string)
    2. Priority level as integer (1=Low, 2=Medium, 3=High, 4=Critical)
    3. Status as integer (0=Pending, 1=InProgress, 2=Completed)

    Create a Task with the given name and priority (convert the integer to the appropriate Priority enum value using static_cast). Then set its status based on the third input. Finally, call display() to show the task details.

For example, with inputs Fix bug, 3, and 1:

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

With inputs Write docs, 1, and 2:

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

With inputs Deploy app, 4, and 0:

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

Notice how the enum classes keep priority and status values completely separate—you can't accidentally compare a Priority to a Status or assign one to the other. The explicit static_cast required to convert between integers and enum values makes the code's intent clear and prevents subtle bugs.

Cheat sheet

C++11 introduced enum classes (scoped enumerations) to provide stronger type safety than traditional C-style enums.

Traditional enums have problems with scope leakage and implicit conversions:

// Traditional enum - problematic
enum Color { Red, Green, Blue };
enum TrafficLight { Red, Yellow, Green };  // Error! Red and Green already defined

int x = Red;  // Implicitly converts to int
if (Red == 0) { }  // Compiles - comparing enum to int

Enum classes solve these issues by requiring scope resolution and preventing implicit conversions:

enum class Color { Red, Green, Blue };
enum class TrafficLight { Red, Yellow, Green };  // OK - no conflict

Color c = Color::Red;      // Must use scope operator
// int x = c;              // Error! No implicit conversion
int x = static_cast<int>(c);  // Explicit conversion required

// if (c == 0) { }         // Error! Can't compare to int
if (c == Color::Red) { }   // OK - comparing same types

You can specify the underlying type for memory control:

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

To convert between enum classes and integers, use explicit casting:

// Integer to enum class
Priority p = static_cast<Priority>(3);

// Enum class to integer
int value = static_cast<int>(p);

Try it yourself

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

using namespace std;

int main() {
    // Read inputs
    string taskName;
    int priorityInt;
    int statusInt;
    
    getline(cin, taskName);
    cin >> priorityInt;
    cin >> statusInt;
    
    // TODO: Create a Task with the given name and priority
    // Use static_cast to convert priorityInt to Priority enum
    
    // TODO: Set the task's status based on statusInt
    // Use static_cast to convert statusInt to Status enum
    
    // TODO: Call display() to show the task details
    
    return 0;
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming