継承 (Inheritance)

class BaseClass
{
}

class SubClass : BaseClass
{
}

継承方法の指示

  • virtual … 派生クラスに、オーバーライドを許可
  • abstract … 派生クラスに、オーバーライドを強制
抽象メソッドと仮想メソッド - 継承 (C# プログラミング ガイド) | Microsoft Learn

virtual … オーバーライドを許可

class BaseClass
{
    public         void Method1() { }
    public virtual void Method2() { }
    public virtual void Method3() { }
}

class SubClass : BaseClass
{
    public          void Method1() { } // CS0108 'SubClass.Method1()' は継承されたメンバー 'BaseClass.Method1()' を非表示にします。非表示にする場合は、キーワード new を使用してください。
    public          void Method2() { } // CS0114 'SubClass.Method2()' は継承されたメンバー 'BaseClass.Method2()' を非表示にします。現在のメンバーでその実装をオーバーライドするには、override キーワードを追加してください。オーバーライドしない場合は、new キーワードを追加してください。
    public override void Method3() { } // OK
}

abstract … オーバーライドを強制

class BaseClass1
{
    public abstract void Method1(); // CS0513 'BaseClass1.Method1()' は抽象ですが、非抽象クラスの 'BaseClass1' に含まれています。
}

abstract class BaseClass2
{
    public abstract void Method1() { } // CS0500 'BaseClass2.Method1()' は abstract に指定されているため本体を宣言できません。
    public abstract void Method2();    // OK
}

class SubClass : BaseClass2 // CS0534 'SubClass' は継承抽象メンバー 'BaseClass2.Method1()' を実装しません。
{
    public          void Method1() { } // CS0114 'SubClass.Method1()' は継承されたメンバー 'BaseClass2.Method1()' を非表示にします。現在のメンバーでその実装をオーバーライドするには、override キーワードを追加してください。オーバーライドしない場合は、new キーワードを追加してください。
    public override void Method2() { } // OK
}

継承の実装

override … メソッドの拡張

virtualやabstractで宣言されているメソッドを、拡張して実装します。

abstract class BaseClass1
{
    public          void Method1() { }
    public virtual  void Method2() { }
    public abstract void Method3();
}

class SubClass : BaseClass1
{
    public override void Method0() { } // CS0115 'SubClass.Method0()': オーバーライドする適切なメソッドが見つかりませんでした。
    public override void Method1() { } // CS0506 'SubClass.Method1()': 継承されたメンバー 'BaseClass1.Method1()' は virtual、abstract または override に設定されていないためオーバーライドできません。
    public override void Method2() { } // OK
    public override void Method3() { } // OK
}

base

派生クラスから、オーバーライドした基本クラス (基底クラス) のメソッドを呼び出せます。base キーワード - C# リファレンス | Microsoft Learn

public override void Method2()
{
    base.Method2();
}

new … メソッドの隠蔽

class BaseClass1
{
    protected virtual void Method1() { }
    protected virtual void Method2() { }
    protected virtual void Method3() { }
    protected virtual void Method4() { }
}

class SubClass : BaseClass1
{
    public    override void Method1() { } // CS0507 'SubClass.Method1()': 'protected' の継承メンバー 'BaseClass1.Method1()' をオーバーライドするときに、アクセス修飾子を変更できません。
    public    new      void Method2() { } // OK
    protected override void Method3() { } // OK
    protected new      void Method4() { } // OK
}

アクセス修飾子の変更

派生クラスでnewで非表示にしたメソッドの、アクセス修飾子を変更する場合を考えます。

class BaseClass1
{
    public  void Method1() { Console.Write("Base - Method1"); }
    public  void Method2() { Console.Write("Base - Method2"); }
    private void Method3() { Console.Write("Base - Method3"); }
    private void Method4() { Console.Write("Base - Method4"); }
}

class SubClass : BaseClass1
{
    public  new void Method1() { Console.Write("Sub - Method1"); }
    private new void Method2() { Console.Write("Sub - Method2"); }
    public  new void Method3() { Console.Write("Sub - Method3"); } // warning CS0109: メンバー 'SubClass.Method3()' は継承されたメンバーを非表示にしません。new キーワードは不要です。
    private new void Method4() { Console.Write("Sub - Method4"); } // warning CS0109: メンバー 'SubClass.Method4()' は継承されたメンバーを非表示にしません。new キーワードは不要です。

    public void Func()
    {
        this.Method1(); // Sub - Method1
        this.Method2(); // Sub - Method2 … 派生クラスのメソッドへアクセス可能なため、それが呼ばれる
        this.Method3(); // Sub - Method3
        this.Method4(); // Sub - Method4
    }
}

派生クラスのインスタンスから呼ぶ場合は、アクセス可能なメソッドが呼ばれます。

SubClass sub = new SubClass();
sub.Method1(); // Sub - Method1
sub.Method2(); // Base - Method2 … 派生クラスのメソッドはprivateなため、基本クラスのそれが呼ばれる
sub.Method3(); // Sub - Method3
sub.Method4(); // error CS0122: 'SubClass.Method4()' はアクセスできない保護レベルになっています

overrideとnewの相違

基本クラスと、それを継承した派生クラスを定義します。

class BaseClass
{
    public virtual void Method1() { Console.Write("Base - Method1"); }
    public virtual void Method2() { Console.Write("Base - Method2"); }
}

class SubClass : BaseClass
{
    public override void Method1() { Console.Write("Sub - Method1"); }
    public new      void Method2() { Console.Write("Sub - Method2"); }
}

次の3通りの場合について、それぞれ呼ばれるメソッドを確認します。

  1. 基本クラスに、基本クラスのインスタンスを格納
  2. 派生クラスに、派生クラスのインスタンスを格納
  3. 基本クラスに、派生クラスのインスタンスを格納
BaseClass c1 = new BaseClass();
c1.Method1(); // Base - Method1 … 基本クラスのメソッドが呼ばれる
c1.Method2(); // Base - Method2

SubClass c2 = new SubClass();
c2.Method1(); // Sub - Method1 … 派生クラスのメソッドが呼ばれる
c2.Method2(); // Sub - Method2

BaseClass c3 = new SubClass();
c3.Method1(); // Sub - Method1 … overrideで拡張されていると、派生クラスのメソッドが呼ばれる
c3.Method2(); // Base - Method2 … newで隠蔽されていると、基本クラスのメソッドが呼ばれる
Microsoft Learnから検索