Enumクラスと強い型付け
CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 80/104。
C++11では、従来のCスタイルの列挙型の欠点に対処するため、enum classes(スコープ付き列挙型とも呼ばれます)が導入されました。これにより、より強い型安全性が提供され、列挙値の意図しない誤用が防止されます。
従来の列挙型には問題があります。値が周囲のスコープに漏れ出し、暗黙的に整数へ変換されるため、見つけにくいバグにつながります。
// 従来のenum - 問題あり
enum Color { Red, Green, Blue };
enum TrafficLight { Red, Yellow, Green }; // エラー!Red と Green は既に定義されています
int x = Red; // 暗黙的に int (0) に変換される
if (Red == 0) { } // コンパイルされる - enum と int を比較列挙型クラスは、値のスコープを限定し、暗黙の変換を防ぐことで、これらの問題を解決します。
enum class Color { Red, Green, Blue };
enum class TrafficLight { Red, Yellow, Green }; // OK - 競合なし
Color c = Color::Red; // スコープ演算子を使用する必要がある
// int x = c; // エラー! 暗黙の変換なし
int x = static_cast<int>(c); // 明示的な変換が必要
// if (c == 0) { } // エラー! intと比較できない
if (c == Color::Red) { } // OK - 同じ型同士の比較メモリを制御するために基底型を指定することもできます:
enum class Status : uint8_t {
Inactive = 0,
Active = 1,
Pending = 2
};Enum クラスは OOP の設計と相性がよく、コードをより読みやすくし、実行時ではなくコンパイル時に型エラーを検出できます。
チャレンジ
簡単異なる優先度レベルとタスクの状態を表すために enum クラスを使用するタスク優先度システムを構築しましょう。これは、enum クラスが型安全性を提供し、従来の enum で発生するようなバグを防ぐ方法を示しています。
コードを3つのファイルに分けて整理します。
TaskTypes.h: タスクシステム用の enum クラスを定義します。Priorityenum クラスを作成し、値としてLow、Medium、High、Criticalを設定します。基底型としてintを指定し、それぞれの値を1、2、3、4とします。Statusenum クラスを作成し、値としてPending、InProgress、Completedを設定します。2つのヘルパー関数を用意します。
priorityToString(Priority p): 優先度を文字列("Low"、"Medium"、"High"、または "Critical")として返しますstatusToString(Status s): 状態を文字列("Pending"、"InProgress"、または "Completed")として返します
Task.h: enum クラスを使用するTaskクラスを定義します。Taskには、名前(文字列)、Priority、Statusを保持させます。コンストラクターは名前と優先度を受け取り、状態のデフォルト値はStatus::Pendingとします。次のメソッドを実装します。
setStatus(Status s): タスクの状態を更新しますgetPriorityValue():static_castを使用して、優先度の基底となる整数値を返しますdisplay(): タスクを次の形式で出力します:[name] - Priority: [priority] (Value: [value]) - Status: [status]
main.cpp: 3つの入力を読み取ります。- タスク名(文字列)
- 優先度レベル(整数)(1=Low、2=Medium、3=High、4=Critical)
- 状態(整数)(0=Pending、1=InProgress、2=Completed)
指定された名前と優先度で
Taskを作成します(static_castを使用して整数を適切なPriorityenum 値に変換します)。次に、3番目の入力に基づいて状態を設定します。最後にdisplay()を呼び出してタスクの詳細を表示します。
たとえば、入力が Fix bug、3、1 の場合:
Fix bug - Priority: High (Value: 3) - Status: InProgress入力が Write docs、1、2 の場合:
Write docs - Priority: Low (Value: 1) - Status: Completed入力が Deploy app、4、0 の場合:
Deploy app - Priority: Critical (Value: 4) - Status: Pendingenum クラスによって、優先度と状態の値が完全に分離されていることに注目してください。Priority を Status と誤って比較したり、一方をもう一方に代入したりすることはできません。整数と enum 値の間の変換に必要な明示的な static_cast によって、コードの意図が明確になり、見つけにくいバグを防止できます。
自分で試してみよう
#include <iostream>
#include <string>
#include "Task.h"
using namespace std;
int main() {
// 入力を読み取る
string taskName;
int priorityInt;
int statusInt;
getline(cin, taskName);
cin >> priorityInt;
cin >> statusInt;
// TODO: 指定された名前と優先度で Task を作成する
// static_cast を使用して priorityInt を Priority 列挙型に変換する
// TODO: statusInt に基づいてタスクのステータスを設定する
// static_cast を使用して statusInt を Status 列挙型に変換する
// TODO: display() を呼び出してタスクの詳細を表示する
return 0;
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
3コンストラクタとデストラクタ
デフォルトコンストラクタパラメータ付きコンストラクタコピーコンストラクタムーブコンストラクタコンストラクタ初期化リスト委譲コンストラクタデストラクタ徹底解説Rule of Three / Five / Zero復習 - Stringクラス6演算子オーバーロード
演算子オーバーロード入門算術演算子のオーバーロード比較演算子のオーバーロードストリーム演算子代入演算子のオーバーロード[] と () の演算子オーバーロード型変換演算子復習 - Matrixクラス自分で練習してみよう: C++オンラインコンパイラ