パープルハット

※当サイトではGoogleアドセンス広告を利用しています

C# abstractとvirtualの違い



abstractとvirtualの違いまとめ

abstract

  • abstractクラスはインスタンス化不可(「new クラス名()」が使えない)ので、継承して初めて利用できる。
  • 関数にもabstractをつけられるが、abstractでは定義のみで中身は継承先で記述(派生クラスでoverrideしないとエラーになる)。
  • 必ずoverrideしたい処理がある場合に派生クラスで書き忘れることが防げる


virtual

  • クラスの前ではなく関数などの前につける。
  • virtual化した関数は、その派生クラスでoverrideせずともエラーが発生せず、継承元に書かれた処理を行う。overrideすることで、処理の追加・削除が行える。
  • 必要に応じてoverrideして関数などの中身を書き換えられる。



abstractの使用例

  • RPGゲームっぽい氷攻撃を仮定。
  • 「Attack」そのものは使用しないのでabstract。
  • 追加効果で「相手は氷漬けになった」と表示。

親となるAttackクラス(abstract)

abstractを付けたクラスなのでこのクラスそのものはインスタンス化できず

var x = new Attack();

としてもエラーが出る。

また、関数は定義のみで中身を書くとエラーが出る

using System;

public abstract class Attack
{
    public Attack()
    {
        Console.WriteLine($"{NAME()}攻撃!");
        Console.WriteLine($"相手に{POWER()}ダメージ");
    }

    //子クラスで継承する
    protected abstract string NAME();
    protected abstract int POWER();
}



Ice(氷攻撃)クラス

overrideした関数はラムダ式っぽく書いてますが、普通の関数の形でも記述可能です。

using System;

public class Ice : Attack
{
    public Ice() : base()
    {
        Console.WriteLine("相手は氷漬けになった");
    }

    protected override string NAME() => "氷";
    protected override int POWER() => 20;
}



動作確認

ソースコード

using System;

public class Call
{
    public static void Main()
    {
        Console.WriteLine("Iceクラス");
        Ice ice = new Ice();
        Console.WriteLine();
    }
}


実行結果

Iceクラス
氷攻撃!
相手に20ダメージ
相手は氷漬けになった





virtualの使用例

  • 某RPGゲームの「スライム」と「メタルスライム」を例に挙げます。
  • ここでは、スライムを継承してメタルスライムを作成します。
  • また、共通なのは攻撃が「メラ」なことで、素早さが異なるものとします。
  • スライム自身もインスタンス化したいので、abstractではなくvirtualを使用します。

親となるSlimeクラス

using System;

public class Slime
{
    public Slime()
    {
        Console.WriteLine($"{NAME()}が現れた!");
    }

    //名前(継承して書き換え)
    protected virtual string NAME() => "スライム";

    //メラを使う(メタルスライムでも同じ挙動なので、継承はしない)
    public void Attack()
    {
        Console.WriteLine($"{NAME()}はメラを唱えた!");
    }

    //素早さ(継承して書き換え)
    public virtual int Speed() => 5;
}



MetalSlime(メタルスライム)クラス

スライムと同じ挙動の関数はそのまま使用します。

using System;

public class MetalSlime : Slime
{
    //名前(継承して書き換え)
    protected override string NAME() => "メタルスライム";

    //素早さ(継承して書き換え)
    public override int Speed() => 999;
}



動作確認

ソースコード

using System;

public class Call
{
    public static void Main()
    {
        Slime slime = new Slime();
        Console.WriteLine($"素早さ:{slime.Speed()}");
        slime.Attack();
        Console.WriteLine();

        MetalSlime metalSlime = new MetalSlime();
        Console.WriteLine($"素早さ:{metalSlime.Speed()}");
        metalSlime.Attack();
    }
}


実行結果

スライムが現れた!
素早さ:5
スライムはメラを唱えた!

メタルスライムが現れた!
素早さ:999
メタルスライムはメラを唱えた!