ざっくりとしたちがい
abstract
- abstract化したクラスはインスタンス化できない(「new クラス名」で生成できない)
- 関数もabstract化することができるが、継承先で必ずoverrideする必要がある。
virtual
- overrideしなくてもエラーは出ない。
- overrideした関数内では「base."継承元の関数名"」とすることで元の処理を行える。
例
- RPGゲームっぽい攻撃コマンド(雷攻撃と氷攻撃)を仮定
- ダメージを与えるという点で2つのクラスは似ているのでダメージを与えるクラスであるAttackを作成し、それを継承するようにする。
- 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(); }
Thunder(雷攻撃)クラス
public class Thunder : Attack { protected override string NAME() => "雷"; protected override int POWER() => 150; }
Ice(氷攻撃)クラス
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(); Console.WriteLine("Thunderクラス"); Thunder thunder = new Thunder(); } }
実行結果
Iceクラス 氷攻撃! 相手に20ダメージ 相手は氷漬けになった Thunderクラス 雷攻撃! 相手に150ダメージ
まとめ
abstract
- 抽象化
- クラスの前につけるとそのクラス自体はインスタンスできなくなる(「new クラス名()」が使えない)。
- abstract化したクラスは変数の型としては使用できる。ただし、その変数に代入できるのは継承したクラスのみ。
- 関数についてもabstractをつけることができるが、abstractしたクラスのみで定義できる。
- abstractしたクラスを継承したクラスを作ることで、abstractした関数などを使用できる。
- 継承元のクラスにabstract関数がある場合、継承した派生クラスでその関数をoverrideしないとエラーになる。
- 必ずoverrideしたい処理がある場合に派生クラスで書き忘れることが防げる。
virtual
- abstractとは異なりクラスの前につけることはできず、関数などの前につけることができる。
- virtual化した関数などを持つクラスを継承したとき、その派生クラスでoverrideを書かなくてもエラーが発生せず、継承元に書かれた処理を行う。overrideすることで、処理の追加・削除が行える。
- 必要に応じてoverrideして関数などの中身を書き換えられる。