C#入門㉕ ポリモーフィズム ── 同じ命令で、違う動きをする
前回は「オーバーライド(親の処理を子で上書きする)」をやりました。
今回は、そのオーバーライドが本領を発揮する仕組み、ポリモーフィズムです。名前は難しそうですが、考え方はシンプルで、とても強力です。
ポリモーフィズムとは、同じ命令を出しても、相手によって違う動きをすることです。
名前の意味
「ポリモーフィズム」は、「いろいろな(ポリ)形(モーフ)」という意味です。日本語では「多態性(たたいせい)」とも言います。
ひとことで言うと、「同じ呼び方なのに、中身が違う」こと。前回のオーバーライドで、すでにその入り口は見ています。
taro.Greet(); // 会社員の山田です
hanako.Greet(); // 学生の田中です
同じ Greet() なのに、会社員と学生で違う動き。これがポリモーフィズムの基本です。今回は、これをもっと強力に使います。
まとめて扱えるのが、すごいところ
前回やった継承を思い出してください。会社員も学生も「Person(人)の一種」でした。
だから、まとめて Person として扱えるんです。
List<Person> people = new List<Person>();
people.Add(new Employee { Name = "山田" }); // 会社員を
people.Add(new Student { Name = "田中" }); // 学生を
people.Add(new Employee { Name = "佐藤" }); // また会社員を
会社員も学生も、ぜんぶ「Person のリスト」に入れられます。中身は別の種類なのに、「人」としてまとめられる。継承のおかげです。
ここからが、ポリモーフィズム
では、このリストの全員に、あいさつさせてみます。
foreach (Person p in people)
{
p.Greet();
}
結果は、こうなります。
会社員の山田です
学生の田中です
会社員の佐藤です
ここが、不思議で、すごいところです。
p は「Person」として扱っているのに、実物が会社員なら会社員のあいさつ、学生なら学生のあいさつになりました。
同じ p.Greet() という1つの命令。でも、実物の種類に応じて、自動的に正しい動きをしてくれる。これがポリモーフィズムです。
なぜ、これが強力なのか
このコードを、もう一度見てください。
foreach (Person p in people)
{
p.Greet(); // 会社員か学生か、気にしていない
}
このループは、相手が会社員か学生かを、いっさい気にしていません。ただ「Person として、Greet を呼ぶ」だけ。あとは、それぞれの実物が、自分に合った動きをしてくれます。
これの何が嬉しいか。たとえば、新しく「公務員」クラスを追加したとします。
class Officer : Person
{
public override void Greet() { Console.WriteLine("公務員の" + Name + "です"); }
}
このとき、さっきのループは、1文字も書き換えなくていいんです。
people.Add(new Officer { Name = "鈴木" });
foreach (Person p in people)
{
p.Greet(); // このコードはそのまま。公務員も正しくあいさつする
}
新しい種類が増えても、それを使う側(ループ)は変えなくていい。変更に、とても強い。これがポリモーフィズムの、本当の威力です。
たとえるなら
ポリモーフィズムは、リモコンの「再生ボタン」のようなものです。
DVDでも、音楽プレーヤーでも、動画アプリでも、「再生」ボタンを押せば、それぞれが正しく再生します。押す側は、中身の違いを知らなくていい。「再生して」と言うだけ。
p.Greet() も同じ。「あいさつして」と言うだけで、会社員も学生も公務員も、それぞれ正しくあいさつする。指示する側は、中身を気にしなくていい。この「気にしなくていい」が、プログラムをシンプルに保つ秘訣です。
つまずきポイント
ポリモーフィズムは、これまでの積み重ねの上に成り立っています。一度で完全に分からなくても、当然です。
成り立つために必要なのは、
- 継承(第23回)… 会社員も学生も Person の一種
- オーバーライド(第24回)… それぞれが Greet を上書き
この2つが土台です。もし「分かりにくいな」と感じたら、前の2回に戻ってみてください。継承とオーバーライドがしっかり分かると、ポリモーフィズムは自然と腑に落ちます。
まとめ
ポリモーフィズムは、同じ命令で、相手によって違う動きをする仕組み。
foreach (Person p in people)
{
p.Greet(); // 実物の種類に応じて、自動で正しく動く
}
- 違う種類を、共通の親(Person)としてまとめて扱える
- 同じ命令でも、実物に合った動きをする
- 新しい種類が増えても、使う側を変えなくていい
- 継承とオーバーライドの上に成り立つ
次回は、オブジェクト指向編の最後。「形だけ決めて、中身は任せる」抽象クラスとインターフェース です。

