C#入門㉖ 抽象クラスとインターフェース ── 形だけ決めて、中身は任せる
前回は「ポリモーフィズム(同じ命令で違う動き)」をやりました。
今回は、オブジェクト指向編の締めくくり。抽象クラスとインターフェースです。「形だけ決めて、中身は各クラスに任せる」という考え方です。少し抽象的ですが、ここまで来たなら大丈夫です。
抽象クラスとインターフェースは、「やるべきこと」だけを決めて、「やり方」は各クラスに任せる仕組みです。
「あいさつは必ずする。でも、やり方は自由」
前回までの Person を思い出してください。子クラスたちは、それぞれ Greet() を上書きしていました。
ここで、こう考えます。
「Person を継承するなら、あいさつは必ず作ってほしい。でも、その中身は、各クラスに任せる」
つまり、
- 「Greet という処理を持つこと」は強制したい
- でも「Greet の中身」は決めない(各クラスが自由に)
この「形だけ決めて、中身は任せる」を実現するのが、抽象クラスとインターフェースです。
抽象クラス ── 中身のないメソッドを持てる
抽象クラスは、abstract(アブストラクト)という印をつけたクラスです。中に「中身のないメソッド」を置けます。
abstract class Person
{
public string Name { get; set; }
public abstract void Greet(); // 中身がない!宣言だけ
}
public abstract void Greet(); を見てください。{ }(中身)がなく、いきなり ; で終わっています。これは「Greet というメソッドを持て。でも中身は、継承する側が書け」という意味です。
継承する子クラスは、この Greet を必ず書かなければいけません。
class Employee : Person
{
public override void Greet() // 書かないとエラー
{
Console.WriteLine("会社員の" + Name + "です");
}
}
書き忘れると、エラーになります。「あいさつは必ず作って」という強制が効いているんです。
抽象クラスは、new できない
もうひとつ特徴があります。抽象クラスは、それ自体は実物を作れません。
Person p = new Person(); // エラー!抽象クラスは new できない
考えてみれば当然です。Person の Greet は中身がない(未完成)のだから、そのままでは動きようがありません。「人」というぼんやりした概念であって、実物にはできない。実物にできるのは、中身を書いた Employee や Student だけ、というわけです。
インターフェース ── 形だけの「約束」
インターフェースは、抽象クラスをもっと突き詰めたものです。中身のあるものは一切持たず、形(やるべきこと)だけを決めます。
interface IGreetable
{
void Greet(); // 形だけ
}
interface(インターフェース)で定義します。中身はいっさいなし。「Greet というメソッドを持つこと」だけを約束します。
(C#では、インターフェースの名前は I で始める慣習があります。IGreetable のように。)
これを使うときは、: でつなぎます。
class Robot : IGreetable
{
public void Greet() // 約束どおり、Greet を実装
{
Console.WriteLine("ピピッ、ロボットです");
}
}
Robot は Person とは無関係ですが、「あいさつできる(IGreetable)」という約束は守っています。
抽象クラスと、インターフェースの違い
2つは似ていますが、役割が少し違います。
- 抽象クラス … 「〜の一種である」関係。共通の中身も持てる(Person を継承する Employee)
- インターフェース … 「〜ができる」という約束。中身は持たない(あいさつできる、飛べる、など)
たとえるなら、
- 抽象クラスは「血筋」… 人という種類を受けつぐ
- インターフェースは「資格・能力」… あいさつできる、という能力を持つ
人でもロボットでも、種類は違っても「あいさつできる」という能力(インターフェース)は、共通して持てる。これがインターフェースの柔軟なところです。
なぜ、こんな仕組みがあるのか
「中身を書かないメソッド」なんて、何の役に立つのか。理由は、前回のポリモーフィズムと繋がります。
「Greet を必ず持つ」と約束させておけば、中身が何であれ、安心して Greet() を呼べるんです。
List<IGreetable> items = new List<IGreetable>();
items.Add(new Employee());
items.Add(new Robot());
foreach (IGreetable item in items)
{
item.Greet(); // 全員 Greet を持つと約束済みなので、安心して呼べる
}
「あいさつできる」と約束したものだけを集めたので、全員に Greet() を呼べる。会社員でもロボットでも。約束(形)を決めることで、ポリモーフィズムが安全に使えるんです。
つまずきポイント
最初は、「中身を書かないものに、何の意味が?」と感じて当然です。
ポイントは、抽象クラスやインターフェースは、それ単体で役に立つものではないということ。「みんなに共通のルールを決める」ための仕組みです。
「全員、あいさつできること」とルールを決めておくと、後でまとめて扱うときにラクになる。いま完全に分からなくても、大丈夫です。「形だけ決めて、中身は任せる、というやり方があるんだな」と知っておけば、実際に必要になったとき「あれか」と思い出せます。
まとめ
抽象クラスとインターフェースは、「やるべきこと」を決めて「やり方」を任せる仕組み。
- 抽象クラス(
abstract)… 中身のないメソッドを持てる。「〜の一種」の関係。new できない - インターフェース(
interface)… 形だけの約束。「〜ができる」という能力 - 子クラスは、決められたメソッドを必ず書く
- 共通のルールを決めることで、ポリモーフィズムが安全に使える
これで、オブジェクト指向(クラス・継承・オーバーライド・ポリモーフィズム・抽象化)が、ひととおり揃いました。ここまでお疲れさまでした。大きな山を越えました。

