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 intEnum 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 typesYou 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
EasyLet'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
Priorityenum class with values:Low,Medium,High, andCritical. Specifyintas the underlying type, with values 1, 2, 3, and 4 respectively.Create a
Statusenum class with values:Pending,InProgress, andCompleted.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 aTaskclass that uses your enum classes.Your
Taskshould store a name (string), aPriority, and aStatus. The constructor should take a name and priority, with status defaulting toStatus::Pending.Implement these methods:
setStatus(Status s)— updates the task's statusgetPriorityValue()— returns the underlying integer value of the priority usingstatic_castdisplay()— prints the task in the format:[name] - Priority: [priority] (Value: [value]) - Status: [status]
main.cpp: Read three inputs:- Task name (string)
- Priority level as integer (1=Low, 2=Medium, 3=High, 4=Critical)
- Status as integer (0=Pending, 1=InProgress, 2=Completed)
Create a
Taskwith the given name and priority (convert the integer to the appropriatePriorityenum value usingstatic_cast). Then set its status based on the third input. Finally, calldisplay()to show the task details.
For example, with inputs Fix bug, 3, and 1:
Fix bug - Priority: High (Value: 3) - Status: InProgressWith inputs Write docs, 1, and 2:
Write docs - Priority: Low (Value: 1) - Status: CompletedWith inputs Deploy app, 4, and 0:
Deploy app - Priority: Critical (Value: 4) - Status: PendingNotice 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 intEnum 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 typesYou 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;
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesC++ Build & CompilationHeader Files & Source FilesNamespaces & ScopeIntroduction to OOP in C++Classes vs ObjectsThe 'this' PointerMethods (Member Functions)Attributes (Data Members)Ctors & Dtors BasicsRecap - Simple Calculator4Class Properties
Instance vs Static MembersGetters and SettersConst Member FunctionsMutable KeywordStatic Methods and VariablesFriend Functions & ClassesRecap - Bank Account Manager7Inheritance
Basic InheritanceInheritance Access LevelsCtor & Dtor Call OrderMethod OverridingVirtual Functions & VTableMultiple InheritanceVirtual InheritanceRecap - Employee Hierarchy2Memory Management
Stack vs Heap MemoryPointers and ReferencesDynamic Memory (new/delete)Smart Pointers in C++RAII in C++Recap - Dynamic Array Manager5Encapsulation
Access Specifiers in C++Access Specifiers In DepthInformation HidingStruct vs ClassNested & Inner ClassesRecap - Student Records System8Polymorphism
Compile vs Runtime PolymorphFunction OverloadingVirtual Functions RevisitedPure Virtual FunctionsAbstract ClassesInterface Design in C++Dynamic Casting & RTTIRecap - Shape Calculator11Advanced OOP Concepts
Composition vs InheritanceMixins via CRTPPimpl IdiomType ErasureEnum Classes & Strong TypingException Handling in OOPCustom Exception Hierarchies3Constructors & Destructors
Default ConstructorParameterized ConstructorCopy ConstructorMove ConstructorConstructor Init ListsDelegating ConstructorsDestructor Deep DiveRule of Three / Five / ZeroRecap - String Class6Operator Overloading
Intro to Operator OverloadArithmetic Operator OverloadComparison Operator OverloadStream OperatorsAssignment Operator Overload[] and () Operator OverloadType Conversion OperatorsRecap - Matrix Class9Templates
Function TemplatesClass TemplatesTemplate SpecializationVariadic TemplatesSFINAE & Type Traits BasicsRecap - Generic Container