プログラミングを試してみたい人向けのC#プログラミングチュートリアル

クラスを継承する

POINT
  • 継承とはクラスに上かぶせしてクラスを作ること
  • 継承により処理の共通化ができる
  • 継承により同じ処理を呼び出しても結果を変えることができる
目次

継承とは

継承とは、クラスに上かぶせしてクラスを作ることです。
継承する場合、次のようにクラスを定義します。
class クラス名 : 親クラス名
{
    変数や処理など
}

継承時は、アクセス修飾子private、publicに加えて継承元だけ使用できるようにするprotectedも使用します。
親クラスの処理や変数(protectedからpublic)を呼び出す場合は、base.メソッド名or変数()で呼び出します。

これにより処理の共通化ができます。

サンプルプログラム
class Program
{
    static void Main()
    {
        // 子クラスのTarouを生成、処理呼出し
        Tarou tarou = new Tarou();
        tarou.WriteName();
        
        System.Console.ReadKey();  // キー入力待ち
    }
}

// 親クラス
class Person
{
    // protectedで子クラスから呼出し可能
    protected void WriteHello()
    {
        System.Console.WriteLine("こんにちは");
    }
    
}

// 子クラス
class Tarou : Person
{
    public void WriteName()
    {
        // baseで親クラスの処理呼出し
        base.WriteHello();
        System.Console.WriteLine("私は太郎です");
    }
}
実行結果
こんにちは
私は太郎です

サンプルプログラムの実行方法はトップページを参照してください。

ポリモーフィズム(多態性)

ポリモーフィズムは同じ処理を呼び出しても処理結果が異なることです。
継承を使うことで、ポリモーフィズムを利用できます。
次のサンプルプログラムでは、Personクラスに対して同じようにWriteNameを呼び出しますが、結果が変わります。
変数としてはPersonクラスですが、実体はTarouとHanakoという別のクラスだからです。
継承を使うと、TarouもHanakoも親であるPersonクラスとして扱いつつ、処理結果はそれぞれ変えるということができるようになります。

結果を変えるには、メソッドの処理を子クラスで上書きします。
メソッドの上書きのことをオーバーライドと言います。
オーバーライドするメソッドは親クラス側でvirtualと記載しておきます。
子クラスのメソッドにはoverrideを記載します。

サンプルプログラム
class Program
{
    static void Main()
    {
        // Tarouを生成して処理呼出し
        Person person = new Tarou();
        person.WriteName();
        
        // Hanakoを生成して置き換える
        person = new Hanako();
        // 同じようにpersonの処理を呼び出しても結果が変わる
        person.WriteName();
        
        System.Console.ReadKey();  // キー入力待ち
    }
}

// 親クラス
class Person
{
    protected void WriteHello()
    {
        System.Console.WriteLine("こんにちは");
    }
    
    // オーバーライドして良いメソッド
    public virtual void WriteName()
    {
        System.Console.WriteLine("私は人間です");
    }
}

// 子クラス1
class Tarou : Person
{
    public override void WriteName()
    {
        base.WriteHello();
        System.Console.WriteLine("私は太郎です");
    }
}

// 子クラス2
class Hanako : Person
{
    public override void WriteName()
    {
        base.WriteHello();
        System.Console.WriteLine("私は花子です");
    }
}
実行結果
こんにちは
私は太郎です
こんにちは
私は花子です

ポリモーフィズムのメリット

ポリモーフィズムを使うことで、実体となる子クラスを切り替えるだけで結果を変えることができます。
また同じように継承したクラスを追加することで、動きの違うパターンを追加していくことができます。
処理を共通化しやすく、パターンの追加もしやすくなるメリットがあります。

次のサンプルでは、入力値によって生成するクラスを変えています。
一度実体となる子クラスを生成してしまえば、子クラスに関わらず同じ処理を呼び出して、結果だけ違うプログラムを作ることができます。
例えば子クラスのJirouを追加して、3入力で次郎が挨拶するようにすることも簡単になります。

サンプルプログラム
class Program
{
    static void Main()
    {
        System.Console.WriteLine("数字を入力してください。1は太郎、2は花子が挨拶します。");
        string input = System.Console.ReadLine();
        
        // 入力値によって生成するクラスを変える
        Person person;
        switch (input)
        {
            case "1":
                person = new Tarou();
                break;
            case "2":
                person = new Hanako();
                break;
            default:
                person = new Person();
                break;
        }
        
        // クラス生成の部分以外、処理は変わらず結果が変わる
        person.WriteName();
        person.WriteJob();

        System.Console.ReadKey();  // キー入力待ち
    }
}

// 親クラス
class Person
{
    protected void WriteHello()
    {
        System.Console.WriteLine("こんにちは");
    }
    
    public virtual void WriteName()
    {
        this.WriteHello();
        System.Console.WriteLine("私は人間です");
    }
    
    public virtual void WriteJob()
    {
        System.Console.WriteLine("私は人間です");
    }
}

// 子クラス1
class Tarou : Person
{
    public override void WriteName()
    {
        base.WriteHello();
        System.Console.WriteLine("私は太郎です");
    }

    public override void WriteJob()
    {
        System.Console.WriteLine("私は会社員です");
    }
}

// 子クラス2
class Hanako : Person
{
    public override void WriteName()
    {
        base.WriteHello();
        System.Console.WriteLine("私は花子です");
    }

    public override void WriteJob()
    {
        System.Console.WriteLine("私は学生です");
    }
}
実行結果
数字を入力してください。1は太郎、2は花子が挨拶します。
1
こんにちは
私は太郎です
私は会社員です

abstract

親クラスを直接使用することがない場合は、abstractを付けて継承を必須とすることができます。
その場合、メソッドもabstractを付けて親クラスには定義のみを記載するだけにすることができます。
abstractのクラスは直接生成する処理を記載すると、コンパイル時にエラーになります。

サンプルプログラム
class Program
{
    static void Main()
    {
        // Person person = new Person();  //abstractクラスは生成しようとするとコンパイルエラーとなる
        Person person = new Tarou();

        person.WriteName();
        
        System.Console.ReadKey();  // キー入力待ち
    }
}

// 必ず継承して使用する親クラス
abstract class Person
{
    protected void WriteHello()
    {
        System.Console.WriteLine("こんにちは");
    }
    
    // 必ずオーバーライドするメソッド
    public abstract void WriteName();
}

// 子クラス
class Tarou : Person
{
    public override void WriteName()
    {
        base.WriteHello();
        System.Console.WriteLine("私は太郎です");
    }
}
実行結果
こんにちは
私は太郎です