継承 基本の使い方

基本文法

継承

継承とはオブジェクト指向言語で重要な概念であるポリモーフィズムを実現するものであり、親となるクラス(基底クラス)を指定することにより派生クラス側では親クラスの機能と自身のクラスに定義された機能とが使えるようになる機能です。

・値型は継承できない
 構造体は暗黙でSystem.ValueTypeを、列挙体はSystem.Enumを継承します
 明示的に親を指定できないし、自身を親とした派生もできない
・単一継承のみで多重継承はできない
 複数のクラスを継承できないが、何かを継承しているクラスを継承することは可能
 インタフェースはいくつでも指定可能
・親クラスを明示的に指定していない場合はObjectクラスが親クラスとなる。
・派生クラスで拡張が予定されている場合はvirtualを指定し派生クラス側ではoverrideを指定する。
・vertual指定がないメソッドを上書きする場合はnewを指定する。

public class BaseClass
{
    public virtual void Test1()
    {
        Console.WriteLine("BaseClass Test1");
    }
 
    public void Test2()
    {
        Console.WriteLine("BaseClass Test2");
    }
}
 
public class ExtendedClass : BaseClass
{
    // オーバーライド
    public override void Test1()
    {
        Console.WriteLine("ExtendedClass Test1");
    }
 
    // 基底クラスにあるメソッドの隠蔽
    new public void Test2()
    {
        Console.WriteLine("ExtendedClass Test2");
    }
 
    private void Test3()
    {
        // 自クラス定義のメソッドを実行
        this.Test1();
        // 親クラス定義のメソッドを実行
        base.Test1();
    }
}

抽象クラス

・自身は親クラスになることを前提とした定義であり、インスタンス化することができない
・通常のフィールドやメソッドの他、実処理の定義がない抽象メソッドを定義することができる
public abstract class AbstructSampleA
{
    public string name = "AbstructSampleA";
    
    public string GetString1()
    {
        return name;
    }
 
    // 抽象メソッド 処理を持たず派生クラスでの実装を予定
    public abstract string GetString();
}

インターフェース

・インスタンス化できず、実現(インタフェースを継承すること)されることを予定している
・クラスは複数のインタフェースを実現することができる
C#8.0以前
・定義できるのはシグネチャのみ(純粋仮想関数のようなもの)
public interface ISampleA
{
    void SampleMethodA();
}
public interface ISampleB
{
    void SampleMethodB();
}
 
public class ImplementSample : ISampleA , ISampleB
{
    public void SampleMethodA(){}
 
    public void SampleMethodB(){}
}
C#8.0以降
・デフォルトインターフェースメソッドという機能が追加され、処理を記述できるようになりました
・フィールドを持てないが多重継承は可能なクラスみたいな感じ

    interface ISample
    {
        // インタフェースにデフォルトメソッドを定義可能
        public void WriteLog() => Console.WriteLine("test");
    }

    class Derivated : ISample
    {

    }

    class Program
    {
        static void Main(string[] args)
        {
            // インタフェース型ならそれを呼べる
            ISample sample = new Derivated();
            sample.WriteLog();

            // 派生クラス型
            Derivated sample2 = new Derivated();
            
            // そんなメソッド無いと怒られる
            //sample2.WriteLog();

            // キャストしてやればOK
            ((ISample)sample2).WriteLog();

            // 当然これもダメ
            var sample3 = new Derivated();
            //sample3..WriteLog();

            // 多重継承可能なのでこうやって呼び分ける必要がある
        }
    }

拡張メソッド

静的メソッドをインスタンスメソッドと同様に呼び出す仕組み
継承関係ではないけど、そうみえなくもない
public class SampleClass
 {
     public string GetSampleString()
     {
         // インスタンスメソッドのように呼べるが別クラスに定義されている
         return this.Test();
     }
 }
 
 static class SampleClassExtension
 {
     // 引数にthisと型を指定する
     public static string Test(this SampleClass sampleClass)
     {
         return "SampleClassExtension";
     }
 }