この章では、複数の選択肢から1つを選んで処理を分ける switch 文と、C++における列挙型(enum class)について学びます。あわせて、enum class を扱うために必要な型変換(static_cast)も先に整理します。
#include <iostream>
using namespace std;
int main() {
int level;
cout << "レベル(1〜3)を入力:";
cin >> level;
switch (level) {
case 1:
cout << "初級です。" << endl;
break;
case 2:
cout << "中級です。" << endl;
break;
case 3:
cout << "上級です。" << endl;
break;
default:
cout << "範囲外です。" << endl;
break;
}
return 0;
}
switch は数値や文字に基づいて処理を分ける構文break を忘れると次の case に処理が流れる(フォールスルー)default はすべての case に当てはまらないときに実行break; がないと、マッチした case 以降のすべての case が続けて実行されてしまいます。必ず書くようにしましょう。
#include <iostream>
using namespace std;
enum Rank { Gold = 1, Silver, Bronze };
int main() {
Rank rank = Silver;
switch (rank) {
case Gold:
cout << "金賞" << endl;
break;
case Silver:
cout << "銀賞" << endl;
break;
case Bronze:
cout << "銅賞" << endl;
break;
default:
cout << "参加賞" << endl;
break;
}
return 0;
}
enum では、定数名が グローバルに展開 される(他の enum と名前がかぶる危険がある)switch 文などでそのまま使えるC++には enum class という列挙型が用意されています。型の安全性と大規模開発でのミス防止を重視した設計です。
| 比較項目 | 通常の enum | enum class |
|---|---|---|
| 定数の書き方 | Gold |
Rank::Gold |
| 名前の漏れ | グローバルに展開される | スコープ内に閉じている |
| 整数への変換 | 自動変換される | 明示的なキャストが必要 |
| 安全性 | 低い | 高い |
enum class Rank { Gold = 1, Silver, Bronze };
Rank::Gold のようにスコープを明示するRank は独自の型名として定義されるこのあと enum class を int に変換する場面が出てきます。先に「型変換」を整理しておきましょう。型変換には2種類あります。
そのまま変換しても安全な型どうしは、コンパイラが自動で変換します。
int n = 3; double d = n; // int → double に自動変換(d は 3.0) double pi = 3.9; int m = pi; // double → int に自動変換(小数点以下は切り捨て、m は 3)
double → int のように情報が失われる変換では、警告が出ることがある「ここで変換する」とコードにはっきり書く方法です。C++では static_cast を使います。
double pi = 3.9; int m = static_cast<int>(pi); // 「int に変換する」と明示(m は 3)
static_cast<変換後の型>(変換したい値)static_cast<int>(pi) で double の値を int に変換します。
(int)pi という書き方より安全で、C++では static_cast が推奨されるenum class は暗黙的変換が禁止されているため、int として扱いたいときは static_cast<int>(...) で明示的に変換します。
enum class を switch で使うには、2つの方法があります。
#include <iostream>
using namespace std;
enum class Rank { Gold = 1, Silver, Bronze };
int main() {
Rank rank = Rank::Silver;
switch (static_cast<int>(rank)) {
case 1:
cout << "金賞" << endl;
break;
case 2:
cout << "銀賞" << endl;
break;
case 3:
cout << "銅賞" << endl;
break;
default:
cout << "参加賞" << endl;
break;
}
return 0;
}
enum class は暗黙の整数変換が禁止されているので、static_cast<int>(rank) で int に変換してから渡すcase 1:)を書く。ただし「1=金賞」という対応を覚えておく必要があるswitch に enum class をそのまま渡し、case 側を Rank::Gold のようにスコープ付きで書く方法です。変換が要らず、こちらの方が読みやすくなります。
#include <iostream>
using namespace std;
enum class Rank { Gold = 1, Silver, Bronze };
int main() {
Rank rank = Rank::Silver;
switch (rank) { // 変換せず、そのまま渡せる
case Rank::Gold:
cout << "金賞" << endl;
break;
case Rank::Silver:
cout << "銀賞" << endl;
break;
case Rank::Bronze:
cout << "銅賞" << endl;
break;
}
return 0;
}
switch(rank) のまま渡し、case Rank::Silver: のようにスコープ付きで書くstatic_cast が不要で、数字(1,2,3)の意味を覚えなくてよいので読みやすいint への変換が必要になるのは、case 6: のように整数リテラルと比べたいときだけ// switch_demo.cpp
#include <iostream>
using namespace std;
int main() {
int day;
cout << "曜日番号(1〜7)を入力:";
cin >> day;
switch (day) {
case 1: cout << "日曜日" << endl; break;
case 2: cout << "月曜日" << endl; break;
case 3: cout << "火曜日" << endl; break;
case 4: cout << "水曜日" << endl; break;
case 5: cout << "木曜日" << endl; break;
case 6: cout << "金曜日" << endl; break;
case 7: cout << "土曜日" << endl; break;
default: cout << "無効な番号です。" << endl; break;
}
return 0;
}
enum class Day { Sun=1, Mon, Tue, Wed, Thu, Fri, Sat }; を定義し、switch 文で曜日を表示するDay::Sat と Day::Sun の場合は「休日」、それ以外は「平日」と追加で表示するswitch (static_cast<int>(day)) として case 1: … と整数で分ける。switch (day) のまま case Day::Sat: … とスコープ付きで書く(変換不要で簡潔)。
次のコードの出力はどれか。
#include <iostream>
using namespace std;
int main() {
int rank = 2;
switch (rank) {
case 1: cout << "金賞" << endl; break;
case 2: cout << "銀賞" << endl; break;
case 3: cout << "銅賞" << endl; break;
default: cout << "参加賞" << endl; break;
}
return 0;
}
rank == 2 により case 2 が実行され、「銀賞」と表示されます。break があるため case 3 以降は実行されません。
次のコードで break を取り除いた場合、rank = 1 のときの出力はどれか。
switch (rank) {
case 1: cout << "金賞" << endl;
case 2: cout << "銀賞" << endl;
case 3: cout << "銅賞" << endl;
default: cout << "参加賞" << endl;
}
break がないため、case 1 にマッチした後もフォールスルーが起き、case 2、case 3、default まで全て実行されます。「金賞」「銀賞」「銅賞」「参加賞」が順番に表示されます。
enum class を使う主な利点として正しいものはどれか。
enum class の主な利点は名前のスコープが型内に閉じており、異なる enum 間での名前衝突を防げることです。通常の enum よりも型安全に使えます。
enum class Color { Red, Green, Blue }; と定義したとき、Color c = Color::Green; を switch に渡すための正しい書き方はどれか。
enum class は暗黙の整数変換が禁止されているため、static_cast<int>(c) で明示的に int に変換する必要があります。Cスタイルキャスト(イ)も動作しますが、C++では static_cast の使用が推奨されます。
switch 文は条件分岐をシンプルに記述できるbreak を忘れるとフォールスルーが起きるので注意static_cast)があるenum は定数名がグローバルに展開されるenum class を使うと名前の衝突を防ぎ、安全に定数を管理できるenum class を switch で扱うには、static_cast<int>() で int に変換するか、case を Rank::Gold のようにスコープ付きで書く