CodeGym /コース /C# SELF /C#におけるメソッドのオーバーライド(override)

C#におけるメソッドのオーバーライド(override)

C# SELF
レベル 20, レッスン 3
使用可能

1. はじめに

例えば、動物園の動物管理アプリがあるとしよう(前の講義で作り始めたやつね)。Animalっていうベースクラスを作って、MakeSoundメソッドで全ての動物が何かしらの音を「出せる」ようにしたんだ。


public class Animal
{
    public virtual void MakeSound()
    {
        Console.WriteLine("動物が音を出す。");
    }
}
        
バーチャルメソッドを持つベースクラス

でも、ライオンとオウムじゃ全然違う音を出すよね。「動物が音を出す」じゃ全然足りない。ここでメソッドのオーバーライドの出番!それぞれの子クラスが自分なりの音を出せるようにしたいよね。

2. シンタックス:overrideの使い方

基本ルール

  • メソッドをオーバーライドしたいなら、ベースクラスでvirtual(またはabstract)で宣言しとく必要がある。
  • 派生クラスでは、同じシグネチャのメソッドの前にoverrideを付ける。

例:ライオンとオウム

public class Lion : Animal
{
    public override void MakeSound()
    {
        Console.WriteLine("ガオー!");
    }
}

public class Parrot : Animal
{
    public override void MakeSound()
    {
        Console.WriteLine("ポッカはバカだ!");
    }
}

これで、動物のリストを作ってそれぞれにMakeSoundを呼ぶと、みんな自分の「声」でしゃべるようになるよ:

Animal[] zoo = new Animal[]
{
    new Lion(),
    new Parrot(),
    new Animal()
};

foreach (var animal in zoo)
{
    animal.MakeSound();
}
// 出力:
// ガオー!
// ポッカはバカだ!
// 動物が音を出す。
重要: C#は、変数が Animal型で宣言されてても、実際の( run-time)オブジェクトの型に合ったメソッドを呼び出すよ!

3. バーチャルメソッドテーブル(v-table)

virtualやoverrideを使うと、コンパイラはクラス用に特別な「バーチャルメソッドテーブル(v-table)」を作るんだ。
ベースクラスの参照でメソッドを呼ぶとき、CLRはこのテーブルを見て「このメソッド、子クラスでオーバーライドされてない?」ってチェックする。もしオーバーライドされてたら、子クラスのバージョンが呼ばれる。
これが「レイトバインディング(late binding)」とかダイナミックポリモーフィズムの「魔法」ってやつ!

4. まとめてみよう:アプリをさらに進化させる

もう一つクラスを追加してみよう:

public class Dog : Animal
{
    public override void MakeSound()
    {
        Console.WriteLine("ワンワン!");
    }
}

そして、動物管理ミニプログラムで使ってみる:

Animal[] zoo = new Animal[]
{
    new Lion(),
    new Parrot(),
    new Dog()
};

foreach (var animal in zoo)
{
    animal.MakeSound();
}

これでコードの拡張性もメンテ性もめっちゃ上がるし、新しい動物を追加するのも超楽しくなるよ!

5. プロパティのオーバーライドとoverrideの戻り値

オーバーライドできるのはメソッドだけじゃない。バーチャルなプロパティやインデクサもオーバーライドできるよ。

public class Animal
{
    public virtual string Name { get; set; } = "動物";
}

public class Lion : Animal
{
    public override string Name { get; set; } = "ライオン";
}

こうやって、特定の種類ごとに情報を細かくできて便利!

6. baseでベースの実装を呼ぶ

ベースメソッドの動作を完全に置き換えるんじゃなくて、ちょっとだけ拡張したい時もあるよね。
そんな時は、オーバーライドしたメソッドの中でbaseを使ってベースの実装を呼び出せばOK。

public class Parrot : Animal
{
    public override void MakeSound()
    {
        base.MakeSound(); // "動物が音を出す。"
        Console.WriteLine("ポッカはバカだ!");
    }
}

この場合、オウムはまず「動物園っぽい」音を出してから、自分の決め台詞「ポッカはバカだ!」を言うよ。

7. 実践で役立つ場面

overrideの仕組みを理解してると、ガチなC#プロジェクトでOOPを使う時にめっちゃ役立つよ。

  • うちの動物園モデル? もうやったね。
  • UI用のカスタムコントロール作成: 標準のビジュアルメソッドをオーバーライドして自分のロジックを追加できる。
  • 柔軟なビジネスロジック: ベースクラスで「骨組み」を作って、具体的な動作は子クラスで実装できる。
  • テストやモック: ユニットテスト用に子クラスでメソッドを簡単に「差し替え」できる。
  • プラグインや拡張: インターフェースや抽象ベースクラス+複数実装、全部正しいオーバーライドのおかげで動く!

8. sealed overrideとチェーン内のバーチャルメソッド

もし「これ以上このメソッドをオーバーライドされたくない!」って時は、sealed overrideを使えばOK:

public class Base
{
    public virtual void Foo() { }
}

public class Middle : Base
{
    public sealed override void Foo() { }
}

public class Last : Middle
{
    public override void Foo() {} // エラー — オーバーライドできない!
}

こうやって、システムの正しい動作にとって重要なところでオーバーライドの連鎖を「封じる」ことができるよ。

9. 新しいメソッド(newキーワード)

ベースクラスのメソッドがvirtualじゃないけど、同じシグネチャで子クラスにメソッドを作りたい時もあるよね。
そんな時はnewキーワードを使う。でもこれはポリモーフィズムじゃなくて、ただの「隠蔽」だよ:

public class Animal
{
    public void MakeSound()
    {
        Console.WriteLine("私は動物だ!");
    }
}

public class Cat : Animal
{
    public new void MakeSound()
    {
        Console.WriteLine("私はネコだよ!");
    }
}

Animal animal = new Cat();
animal.MakeSound(); // "私は動物だ!"
Cat cat = new Cat();
cat.MakeSound(); // "私はネコだよ!"

ここでは、呼び出し時の変数の型が全てを決める!だから、本当のダイナミックポリモーフィズムをやりたいなら、virtual+overrideの組み合わせを使おう。

10. メソッドオーバーライドでよくあるミス

ミスその1: virtual、abstract、overrideで宣言されてないメソッドをオーバーライドしようとする。
C#では普通のメソッドはオーバーライドできないよ。ベースクラスのメソッドに特別な修飾子(virtual、abstract、override)が付いてないと、派生クラスでoverrideを書いてもコンパイルエラーになる。

ミスその2: メソッドのシグネチャが一致してない。
本当にオーバーライドしたいなら、名前・戻り値の型・パラメータがベースクラスのメソッドと完全一致してないとダメ。ちょっとでも違う(例えばパラメータの型が違う)と、新しいメソッドが作られるだけで、オーバーライドにはならないよ。

ミスその3: override修飾子を付け忘れる。
ベースクラスと同じシグネチャのメソッドを定義しても、overrideを付けなかったら、コンパイラはそれをオーバーライドとは見なさない。これはメソッドの隠蔽(別で説明するよ)って呼ばれる。こうなると、ベース型の変数でメソッドを呼ぶと、ベースのメソッドが呼ばれて、思った通りに動かないから注意!

2
タスク
C# SELF, レベル 20, レッスン 3
ロック未解除
メソッドのオーバーライドによるポリモーフィズム
メソッドのオーバーライドによるポリモーフィズム
2
タスク
C# SELF, レベル 20, レッスン 3
ロック未解除
base を使った基本実装の利用
base を使った基本実装の利用
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION