Enums & enum class

An enum gives friendly names to a fixed set of related values — directions, days, states, status codes. Instead of scattering magic numbers like 0 , 1 , 2 through your code, you write Color::Red . This lesson covers plain enums, the safer modern enum class , custom values, and how to print them.

Learn Enums & enum class in our free C++ course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick recall.

Part of the free C++ course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

An enum is like the gear selector in a car: P, R, N, D. There's a small, fixed set of valid positions, each with a clear name. You'd never label them "0, 1, 2, 3" on the dashboard — the words prevent mistakes. A plain enum is like a loose lever that can slip into a number you didn't intend; an enum class is a precise gate that only lets you select a named, valid position. That extra safety is why modern C++ favors enum class .

1. Plain (Unscoped) Enums

The classic enum defines named constants that start at 0 and count up. They convert to int automatically and their names live in the surrounding scope. That convenience is also their weakness — names can clash and values get compared to raw numbers by accident.

2. The Safer enum class

A scoped enum keeps its names behind the type name ( Color::Red ) and refuses to convert to int without an explicit cast. This prevents accidental comparisons and name clashes, which is why it's the recommended default in modern C++.

3. Custom Underlying Values

You can assign explicit numbers to enum members — perfect for things like HTTP status codes or error codes that have meaningful values. Any members you leave unspecified keep counting up from the previous one.

4. Printing Enums with a switch

Since an enum stores a number, not a word, cout can't print a readable name on its own. The standard pattern is a small function that takes the enum and returns a std::string via a switch — clear, fast, and easy to extend.

5. Choosing the Underlying Type

By default an enum is backed by int . You can pin it to a smaller type — like unsigned char for a single byte — when memory matters or a binary format requires it. Converting a raw number back into the enum needs an explicit static_cast , and you should validate the number first.

These lines define a scoped enum and print one member as an int. Reorder them so the program prints 2 .

Why: the enum class must be declared before main can use it. Inside main you create the variable (B then A), then print it — and because enum class won't convert implicitly, you need the explicit static_cast<int> . Large is the third member (Small=0, Medium=1, Large=2), so it prints 2 .

Predict the output before revealing each answer.

2 — a plain enum converts to int automatically, and C is the third member (A=0, B=1, C=2).

7 — X is 5, so Y is 6 and Z is 7 (counting continues from the explicit value).

Compile error — an enum class has no implicit conversion to int, so cout can't print it without a static_cast .

Define an OrderStatus enum, map it to a label with a switch, and detect terminal states. Match the expected output in the comments.

Practice quiz

What is the main difference between a plain enum and an enum class?

  • enum class keeps its names scoped and does not implicitly convert to int; a plain enum leaks names and converts to int automatically
  • enum class cannot have custom values, but a plain enum can
  • A plain enum is the modern, preferred form added in C++11
  • There is no difference; they are interchangeable keywords

Answer: enum class keeps its names scoped and does not implicitly convert to int; a plain enum leaks names and converts to int automatically. A scoped enum class avoids name leaks and accidental int comparisons, which is why modern C++ prefers it.

Given enum class Color { Red, Green, Blue };, how do you print the value of c = Color::Green?

  • cout << c;
  • cout << static_cast<int>(c);
  • cout << Color::c;
  • cout << (int)Color;

Answer: cout << static_cast<int>(c);. An enum class has no implicit conversion to int, so you must cast: static_cast<int>(c). Printing it directly is a compile error.

For enum class Level { Low = 1, Medium, High };, what is static_cast<int>(Level::High)?

  • 1
  • 2
  • 3
  • 0

Answer: 3. Low is 1, so Medium auto-increments to 2 and High to 3.

What does cout << C; print for plain enum E { A, B, C };?

  • A compile error
  • 2
  • C
  • 3

Answer: 2. A plain enum converts to int automatically, and C is the third member (A=0, B=1, C=2).

How do you pin a scoped enum's storage to a single byte?

  • enum class Suit : unsigned char { ... };
  • enum class Suit byte { ... };
  • enum Suit(1) { ... };
  • You cannot change an enum's underlying type

Answer: enum class Suit : unsigned char { ... };. Specifying the underlying type, e.g. : unsigned char, pins the storage size (here 1 byte).

To access a member of enum class Color { Red, Green, Blue };, you must write:

  • Red
  • Color.Red
  • Color::Red
  • Color->Red

Answer: Color::Red. Scoped enum members must be qualified with the type name and ::, so Color::Red.

What is the standard way to turn an enum into a readable name?

  • cout prints the name automatically
  • A function with a switch that returns a std::string per case
  • Calling .name() on the enum value
  • Using static_cast<string>(value)

Answer: A function with a switch that returns a std::string per case. Since an enum stores a number, not text, you write a small function (usually a switch) that returns the right string.

For enum class HttpStatus { Ok = 200, Created, NotFound = 404 };, what is the value of Created?

  • 200
  • 201
  • 1
  • 404

Answer: 201. Unspecified values keep counting up from the previous one, so Created is 201.

Why must you validate a number before static_cast<Color>(n)?

  • The cast will not compile otherwise
  • An out-of-range value produces an enum with no matching name
  • static_cast cannot convert int to an enum at all
  • It automatically clamps to the nearest valid value

Answer: An out-of-range value produces an enum with no matching name. Casting an out-of-range int, like static_cast<Color>(99), compiles but yields an invalid enum value, so you must range-check first.

What is sizeof(Suit) for enum class Suit : unsigned char { Clubs, Diamonds, Hearts, Spades };?

  • 1
  • 2
  • 4
  • 8

Answer: 1. The underlying type is unsigned char, so the enum occupies exactly 1 byte.