Skip to content
C++ Better Explained
Go back
C++ enum class vs enum: Scoped Enums Explained

C++ enum class vs enum: Scoped Enums Explained

An enum gives names to a set of related constants — like Red, Green, Blue. C++11 added a stronger version called enum class (a “scoped enum”). The difference matters: enum class keeps its names tidy inside its own scope and refuses to silently turn into an integer, which stops two whole categories of bugs.


Plain enum: The Original

#include <iostream>
using namespace std;

enum Color { Red, Green, Blue };

int main() {
    Color c = Green;         // no scope needed
    cout << c << "\n";       // prints 1 — it's really just an int
    return 0;
}

By default the values are numbered from 0, so Red is 0, Green is 1, Blue is 2. Notice two things: you write Green directly (no prefix), and it prints as 1 because a plain enum converts to int on its own.

Those two conveniences are also the two problems.


Problem 1: Name Clashes

Plain enum names spill into the surrounding scope. So two enums can’t share a value name:

enum Color   { Red, Green, Blue };
enum Traffic { Red, Yellow, Green };   // ERROR: Red and Green already defined

The compiler rejects this because Red and Green already exist. In a large program with many enums, these collisions are common and annoying.


Problem 2: Accidental int Conversions

Because a plain enum is basically an int, nonsense comparisons compile without complaint:

enum Color { Red, Green, Blue };
enum Fruit { Apple, Banana, Cherry };

Color c = Red;
if (c == Apple) {    // compiles! both are 0, so this is TRUE
    // ...a bug that the compiler never warned you about
}

Red and Apple are both 0, so the comparison is silently true. That’s a real bug the language happily lets through.

If you're looking to go deeper with C++, the C++ Better Explained Ebook is perfect for you — whether you're a complete beginner or looking to solidify your understanding. Just $19.

enum class Fixes Both

Add the keyword class (or struct) and both problems disappear:

#include <iostream>
using namespace std;

enum class Color   { Red, Green, Blue };
enum class Traffic { Red, Yellow, Green };   // fine — names are scoped

int main() {
    Color c = Color::Red;      // must qualify with Color::
    Traffic t = Traffic::Red;  // no clash with Color::Red

    // if (c == t) { }         // ERROR: different types, won't compile
    // int n = c;              // ERROR: no implicit conversion to int

    if (c == Color::Red) {
        cout << "It's red\n";
    }
    return 0;
}

Now Color::Red and Traffic::Red coexist peacefully, and mixing a Color with a Traffic — or with an int — is a compile error instead of a silent bug. This is safer because the compiler catches the mistake the moment you write it.


Converting a Scoped Enum to int

Sometimes you genuinely need the underlying number (for printing, indexing, or serialising). Scoped enums require an explicit cast, which makes the intent obvious:

enum class Color { Red, Green, Blue };

Color c = Color::Blue;
int n = static_cast<int>(c);   // n == 2
std::cout << n << "\n";

The explicit static_cast is a feature, not a chore — it documents “yes, I really want the integer here.”


Choosing the Underlying Type

Both kinds of enum let you pick the underlying integer type, which is handy for saving space or matching a protocol:

enum class Status : unsigned char { Ok, Warning, Error };  // stored in 1 byte

Quick Comparison

Featureenum (plain)enum class (scoped)
IntroducedC++98C++11
Access valuesGreenColor::Green
Converts to int automatically?YesNo (explicit cast)
Names leak into scope?YesNo
Name clashes possible?YesNo
Recommended default?NoYes

The Takeaway

Reach for enum class by default in new code. The extra Color:: prefix is a tiny price for eliminating name clashes and accidental integer comparisons. Use a plain enum only when you specifically want the implicit int behaviour — for example, bit flags — and even then, do it on purpose.



Take Your C++ Further

If you’re looking to go deeper with C++, the C++ Better Explained Ebook is perfect for you — whether you’re a complete beginner or looking to solidify your understanding. Just $19.

👉 Get the C++ Better Explained Ebook — $19

📋

Free Download: The 10 Mistakes Every C++ Beginner Makes

A free 1-page checklist that shows the exact traps that slow down every C++ beginner — so you can avoid them from day one.

🔒 No spam. Unsubscribe anytime.


Share this post on:

Written by

Sahil Bora

Software Engineer. Author and creator of C++ Better Explained.


Next Post
C++ float vs double: Which One Should You Use?

Keep Learning