PR

[C# クラス] 仮想メソッドを使った多態性(ポリモーフィズム)の話

クラスの継承の記事の続きです。まだ読んでないよという人はこちら、

[C# 入門] クラスの継承について
今回はクラスの継承についてです。継承を使うと、元にするクラスの持つ機能(メンバー)を受け継いだ新しいクラスを作ることができます。 継承のもとになるクラスのことを基底クラス、基底クラスのメンバーを継承するクラスのことを派生クラスといいます。 ...

今回は仮想メソッドというものを使って多態性(ポリモーフィズム)の話をします。
多態性とはざっくりいうと、1つのオブジェクトが中に入っているインスタンスに応じて異なる動作をすることです。

スポンサーリンク

仮想メソッドの話

継承のもとになるクラスを基底クラス、継承したクラスを派生クラスといいます。
基底クラス型の変数には派生クラスのインスタンスを入れることができます。

using System;
// 基底クラス
class BaseClass { }
// 派生クラス
class SampleClass : BaseClass { }
// メインプログラム
class Program
{
    public static void Main()
    {
        // 基底クラス型の変数に派生クラスのインスタンスを入れることができる
        BaseClass b = new SampleClass();
    }
}

派生クラスが基底クラスのメソッドを上書きしている場合、基底クラス型の変数からメソッドを呼び出すとどうなるでしょうか?

using System;
// 基底クラス
class BaseClass
{
    public void Method() => Console.WriteLine("基底クラスのメソッドです");
}
// 派生クラス
class SampleClass : BaseClass
{
    // 基底クラスのメソッドを上書き
    public new void Method() => Console.WriteLine("派生クラスのメソッドです");
}
// メインプログラム
class Program
{
    public static void Main()
    {
        // 基底クラス型の変数に派生クラスのインスタンスを入れることができる
        BaseClass b = new SampleClass();

        // どちらのMethodが呼ばれる?
        b.Method();
    }
}
基底クラスのメソッドです

という感じで、基底クラスのメソッドが呼び出されます。
で、派生クラスのインスタンスを入れてるんだから派生クラス側のメソッドを呼び出して欲しい!というときに仮想メソッドを使います。

スポンサーリンク

仮想メソッドの使い方

基底クラスのメソッドに virtualキーワードを付けると仮想メソッドになります。
で、派生クラス側で overrideキーワードを付けて仮想メソッドを上書きすると、
派生クラスのインスタンスが入った基底クラス型の変数からメソッドを呼び出したときに派生クラス側のメソッドが実行されます。

using System;
// 基底クラス
class BaseClass
{
    // virtualを付けると仮想メソッドになる
    public virtual void Method() => Console.WriteLine("基底クラスのメソッドです");
}
// 派生クラス
class SampleClass : BaseClass
{
    // overrideを付けて仮想メソッドを上書き
    public override void Method() => Console.WriteLine("派生クラスのメソッドです");
}
// メインプログラム
class Program
{
    public static void Main()
    {
        // 基底クラス型の変数に派生クラスのインスタンスを入れることができる
        BaseClass b = new SampleClass();

        // どちらのMethodが呼ばれる?
        b.Method();
    }
}
派生クラスのメソッドです

virtualキーワードはabstractと違って必ず上書きしなければいけない、というわけではありません。上書きは任意になります。
上書きしない場合は、基底クラスの仮想メソッドが呼ばれます。

using System;
// 基底クラス
class BaseClass
{
    // virtualを付けると仮想メソッドになる
    public virtual void Method() => Console.WriteLine("基底クラスのメソッドです");
}
// 派生クラス(このクラスでは仮想メソッドを上書きしない)
class SampleClass : BaseClass { }
// メインプログラム
class Program
{
    public static void Main()
    {
        // 基底クラス型の変数に派生クラスのインスタンスを入れる
        BaseClass b = new SampleClass();
        // 基底クラスのメソッドが呼ばれる
        b.Method();
    }
}
基底クラスのメソッドです
スポンサーリンク

多態性の話

仮想メソッドを使うと入っているインスタンスによって実行する処理を変えるということができます。

using System;
// 基底クラス
class BaseClass
{
    // virtualを付けると仮想メソッドになる
    public virtual void Method() => Console.WriteLine("基底クラスのメソッドです");
}
// 派生クラスA
class SampleClass_A : BaseClass
{
    // overrideを付けて仮想メソッドを上書き
    public override void Method() => Console.WriteLine("派生クラスAのメソッドです");
}
// 派生クラスB
class SampleClass_B : BaseClass
{
    // overrideを付けて仮想メソッドを上書き
    public override void Method() => Console.WriteLine("派生クラスBのメソッドです");
}
// メインプログラム
class Program
{
    public static void Main()
    {
        // 基底クラス型の変数に入れる派生クラスのインスタンスで処理を切り替えて実行できる
        BaseClass b;
        // 派生クラスAのインスタンスを入れてメソッドを呼び出す
        b = new SampleClass_A();
        b.Method();
        // 派生クラスBのインスタンスを入れてメソッドを呼び出す
        b = new SampleClass_B();
        b.Method();
    }
}
派生クラスAのメソッドです
派生クラスBのメソッドです

このように、1つのオブジェクトが入っているインスタンスによって異なる動きをすることを多態性(ポリモーフィズム)といいます。

スポンサーリンク

仮想(virtual)に出来るメンバー

virtualキーワードは、メソッド、プロパティ、インデクサーに付けることができます。

using System;
// 基底クラス
class BaseClass
{
    // 仮想メソッド
    public virtual void Method() => Console.WriteLine("基底クラスのメソッドです");
    // 仮想プロパティ
    public virtual string Property { get => "基底クラスのプロパティです"; }
    // 仮想インデクサー
    public virtual string this[string key] { get => "基底クラスのインデクサーです"; }
}
// 派生クラス
class SampleClass : BaseClass
{
    // 仮想メソッドを上書き
    public override void Method() => Console.WriteLine("派生クラスのメソッドです");
    // 仮想プロパティを上書き
    public override string Property { get => "派生クラスのプロパティです"; }
    // 仮想インデクサーを上書き
    public override string this[string key] => "派生クラスのインデクサーです";
}
// メインプログラム
class Program
{
    public static void Main()
    {
        // 基底クラス型の変数に派生クラスのインスタンスを入れる
        BaseClass b = new SampleClass();
        // 各メンバーを呼んでみる
        b.Method();
        Console.WriteLine(b.Property);
        Console.WriteLine(b["aaa"]);
    }
}
派生クラスのメソッドです
派生クラスのプロパティです
派生クラスのインデクサーです

イベント宣言にも付けられるみたいなのですが使い方がよく分からないのでわかる人教えてください。


もう少し続きます、次は基底クラスと派生クラスの型変換の話です。

[C# クラス] キャストで型変換(基底クラス⇔派生クラス)
仮想メソッドを使った多態性(ポリモーフィズム)の話では基底クラス型の変数に派生クラスのインスタンスを入れることができると書きました。 その基底クラス型の変数から呼び出せるのは基底クラスにあるメンバーだけになります。では、派生クラスにある独自...

C# 記事まとめページに戻る(他のサンプルコードもこちら)

C# プログラミング講座
C#についての記事まとめページです。開発環境VisualStudioのインストール方法や使い方、プログラミングの基礎知識についてや用語説明の記事一覧になっています。講座の記事にはすぐに実行できるようにサンプルコードを載せています。

コメント