前回は「継承(クラスの性質を受けつぐ)」をやりました。

今回は、その継承と深く関わる仕組み、オーバーライドです。親から受けついた処理を、子で「上書き」する仕組みです。

オーバーライドとは、親クラスのメソッドを、子クラスで作り直すことです。

受けついだだけだと、みんな同じになる

前回、Person(人)を親にして、いろんなクラスが継承しました。

class Person
{
    public string Name { get; set; }
    public void Greet() { Console.WriteLine(Name + "です"); }
}

class Employee : Person { ... }   // 会社員
class Student : Person { ... }    // 学生

このままだと、会社員も学生も、Greet()まったく同じ「○○です」になります。親から受けついだ、同じあいさつだからです。

でも、こうしたくなりませんか。

  • 会社員 → 「会社員の山田です」
  • 学生 → 「学生の田中です」

受けついだあいさつを、それぞれのクラスらしく作り変えたい。これを実現するのが、オーバーライドです。

書き方を見てみる

まず、親のメソッドに「上書きしてもいいよ」という印をつけます。virtual(バーチャル)です。

class Person
{
    public string Name { get; set; }

    public virtual void Greet()   // virtual = 上書きを許可
    {
        Console.WriteLine(Name + "です");
    }
}

そして、子のクラスで override(オーバーライド)を使って、上書きします。

class Employee : Person
{
    public override void Greet()   // override = 上書きする
    {
        Console.WriteLine("会社員の" + Name + "です");
    }
}

class Student : Person
{
    public override void Greet()   // 学生らしく上書き
    {
        Console.WriteLine("学生の" + Name + "です");
    }
}
  • virtual(親)… 「このメソッドは、上書きしてもいい」
  • override(子)… 「親のこのメソッドを、上書きします」

このペアで、受けついた処理を作り変えられます。

使ってみる

それぞれ呼んでみると、こうなります。

Employee taro = new Employee();
taro.Name = "山田";

Student hanako = new Student();
hanako.Name = "田中";

taro.Greet();     // 会社員の山田です
hanako.Greet();   // 学生の田中です

同じ Greet() でも、会社員と学生で、違うあいさつになりました。それぞれのクラスで上書きしたからです。

共通の部分は親から受けつぎつつ、そのクラスらしい部分だけ作り変える。これがオーバーライドの便利なところです。

親の処理も使いたいとき ── base

「親のあいさつを活かしつつ、少し足したい」こともあります。そんなときは base(ベース)で、親の処理を呼べます。

class Employee : Person
{
    public override void Greet()
    {
        base.Greet();                      // まず親のあいさつ(○○です)
        Console.WriteLine("よろしくお願いします");  // そのあと、追加
    }
}
山田です
よろしくお願いします

base.Greet() で、親の Greet()(○○です)をそのまま使い、その後に自分の処理を足しました。「親のをベースに、少し足す」という使い方です。

つまずきポイント

初心者がよく忘れるのが、親に virtual をつけることです。

class Person
{
    public void Greet() { ... }   // virtual がない
}

class Employee : Person
{
    public override void Greet() { ... }   // 上書きできない!エラー
}

親が「上書きしてOK(virtual)」と言っていないのに、子が上書き(override)しようとすると、エラーになります。

「親に virtual、子に override」はペアです。どちらか片方では成り立ちません。オーバーライドでつまずいたら、まず「親に virtual はあるか?」を確認してみてください。

まとめ

オーバーライドは、親のメソッドを子で作り直す仕組み。

class Person
{
    public virtual void Greet() { ... }    // 親:virtual で許可
}

class Employee : Person
{
    public override void Greet() { ... }   // 子:override で上書き
}
  • 受けついた処理を、そのクラスらしく作り変えられる
  • virtual(親)と override(子)はペア
  • base で、親の処理も呼べる

次回は、このオーバーライドが本領を発揮する ポリモーフィズム です。少し不思議で、とても強力な仕組みです。