仕事でMicrosoft関係のものを扱うようになったので、これを機にちょいと古いMacBook ProからSurface Pro 4に買い替えたので、それにVisual Studio Communityを入れてC#で遊んでいる。
昨日、Microsoft Virtual AcademyでC#を勉強していて、どうにも動きが良くわからんと思った「派生クラスにおいて基底クラスのメソッドをnewまたはoverrideし、それらを基底クラスにキャストして呼び出したときにどういう動きをするか」についてちょっと整理してみた。
派生と継承
基底クラスを「派生」(Derive)したクラスを作成すると、基底クラスのプロパティ、メソッドが子クラスに「継承」(Inherit)される
ということらしい。
ソースコード
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication2
{
class BaseClass
{
public static void Main()
{
var baseClass = new BaseClass();
var overRide = new OverrideClass();
var newclass = new NewClass();
baseClass.Name();
baseClass.Bow();
((BaseClass) overRide).Name();
((BaseClass) overRide).Bow();
((BaseClass) newclass).Name();
((BaseClass) newclass).Bow();
Console.ReadLine();
}
internal virtual void Name()
{
Console.WriteLine("BaseClass: Name");
}
internal virtual void Bow()
{
Console.WriteLine("BaseClass: Bow");
}
}
class OverrideClass: BaseClass
{
internal override void Name()
{
Console.WriteLine("OverrideClass: Name");
}
}
class NewClass: BaseClass
{
internal new void Name()
{
Console.WriteLine("NewClass: Name");
}
}
}
出力結果
BaseClass: Name
BaseClass: Bow
OverrideClass: Name
BaseClass: Bow
BaseClass: Name
BaseClass: Bow
考察
Overrideクラスと、NewクラスをそれぞれBaseClassから派生させた。つまり、OverrideクラスとNewクラスには、それぞれName()とBow()とが継承されている。そこで、OverrideクラスではName()をOverrideし、NewクラスではName()をNewで書き換えている。
したがって、BaseClass, OverrideClass, NewClassのBow()メソッドは、すべてBaseClassのBow()が呼ばれている。面白いのは、OverrideしたほうのName()は自身を呼んでいるが、NewしたほうのName()は基本クラスを呼び出している点だ。
C#の言語仕様によると、NewとOverrideは以下のように説明されている。
New修飾子
new キーワードを宣言の修飾子として使用すると、基底クラスから継承されたメンバーを明示的に隠ぺいできます。 継承されたメンバーを隠ぺいすると、派生バージョンのメンバーで基底クラスのバージョンが置き換えられます。
Override修飾子
override メソッドは、基本クラスから継承されたメンバーの新しい実装を提供します。
Newは隠ぺいしているだけ(→基底クラスにキャストしたときには、基底クラスのものをそのまま呼び出す)、Overrideは上書きしている(→基底クラスにキャストしたときには、自身のものを呼び出す)ということらしい。
合っているのか……。実際の動きから考察した結果だけど、基本的なところが抜けてるからちゃんと説明できない。