【Unity C# 復習】virtual/overrideのおさらい
はじめに
C#の復習もかねて、基底クラス・派生クラスのメソッド呼び出しにまとめたいと思います。
記事中のクラス図は一般的なクラス図と書き方が異なるものですが、ご了承ください。
実行環境は ゲームエンジンUnity の C# を想定しています。
ケース1 : ClassA a = new ClassA()
ClassA
というクラスを作成してみます。
public class ClassA
{
public void Foo()
{
Debug.Log("ClassA :: Foo()");
}
}
メソッド実行
そして、以下のようなメソッドを呼び出しを実行します。
ClassA a = new ClassA();
a.Foo();
実行結果
ClassA
の Foo()
メソッドが実行されます。
ケース2 : ClassA2 a = new ClassA()
次に、 ClassA
を継承した ClassA2
を作成します。
public class ClassA2 : ClassA
{
}
メソッド実行
そして、次のようなメソッド呼び出しを書いてみます。
ClassA2 a = new ClassA();
a.Foo();
結果
これはコンパイルエラーになり、実行することができません。
ClassA
は ClassA2
を知らないので、コンパイルエラーになります。
ケース3 : ClassA a = new ClassA2()
今度は、以下のようなメソッド呼び出しを書いてみます。
ClassA a = new ClassA2();
a.Foo();
結果
ClassA
の Foo
メソッドが実行されます。
ClassA2
は ClassA
を知っており、コンパイルエラーにはなりません。
ケース4 : 派生クラスにFooメソッドを定義
ここで、新たに ClassA2
にも Foo
というメソッドを定義してみます。
public class ClassA2 : ClassA
{
public void Foo()
{
Debug.Log("ClassA2 :: Foo()");
}
}
ClassA
も Foo
メソッドを持っています。
public class ClassA
{
public void Foo()
{
Debug.Log("ClassA :: Foo()");
}
}
メソッド実行
そして、以下のような Foo
メソッド呼び出しを実行します。
ClassA a = new ClassA2();
a.Foo();
結果
ClassA
の Foo
メソッドが実行されます。ClassA2
の Foo
メソッドは実行されません。
ClassA2
のメソッドが呼ばれるようにしたい場合、ClassA
の Foo
にはvirtual
をつける必要があります。
ケース5 : virtual/override
ClassA
のFoo
にvirtual
, ClassA2
のFoo
にoverride
をつけます。
public class ClassA
{
public virtual void Foo()
{
Debug.Log("ClassA :: Foo()");
}
}
public class ClassA2 : ClassA
{
public override void Foo()
{
Debug.Log("ClassA2 :: Foo()");
}
}
メソッド実行
そして以下のようなメソッド呼び出しを実行します。
ClassA a = new ClassA2();
a.Foo();
結果
ClassA2
の Foo
メソッドが実行されます。
しかし、今度はClassA
のFoo
メソッドが実行されなくなってしまいました。
ClassA
と ClassA2
両方の Foo
メソッドを実行したい場合は、base.Foo()
を呼びます。
ケース6 : base.Foo()
ClassA2
の Foo
メソッドの中で、base.Foo()
を呼び出します。
public class ClassA2 : ClassA
{
public override void Foo()
{
base.Foo();
Debug.Log("ClassA2 :: Foo()");
}
}
メソッド実行
そして、以下のようなメソッド実行を呼び出してみます。
ClassA a = new ClassA2();
a.Foo();
結果
ClassA2
の Foo
メソッドから ClassA
の Fooメソッドが呼ばれます。
ケース7 : overrideを書き忘れた場合
ClassA2
にoverride
を書き忘れた場合はClassA2
のFoo
は実行されません。
public class ClassA
{
public virtual void Foo()
{
Debug.Log("ClassA :: Foo()");
}
}
public class ClassA2 : ClassA
{
public void Foo()
{
Debug.Log("ClassA2 :: Foo()");
}
}
メソッド実行
ClassA a = new ClassA2();
a.Foo();
結果
ClassA
のメソッドが実行されます。
まとめ
これは私個人の考えですが、メソッドにvirtual
をつけるかどうかは以下のように判断すると良さそうです。
- 派生先で挙動が変わる可能性があるメソッドに関しては
virtual
をつける - 派生先でも挙動が変わらないメソッドに関しては
virtual
をつけない
Discussion