クラスの継承
C#では継承は以下のように書く。
class Person { public string Name { get; set; } public int Age { get; set; } } class Student : Person { public int Id { get; set; } }
継承元を指定せず定義したクラスは全てobject型を継承する。
静的な型と動的な型
ビルド時に確定する方を静的な型という。変数の型は宣言時に決まっており、実行時に変化することがないので、静的な型である。静的な型はtypeof演算子で調べる。
ビルド時に型が確定せず、実行時に変化する可能性がある型を動的な型という。動的な型はGetTYpeメソッドで調べる。
基底クラスのコンストラクターを明示的に呼び出す
class Person { public string Name { get; set; } public int Age { get; set; } public Person(string name, int age) { this.Name = name; this.Age = age; } } class Student : Person { public int Id { get; set; } public Student(string name, int age, int id) : base(name, age) { this.Id = id; } }
基底クラスのメソッドの隠蔽
newキーワードを使うことで、基底クラスのメソッドと同じシグネチャのメソッドを定義することができる。これによって、基底クラスのメソッドは呼び出されなくなるため、これを基底クラスのメソッドの隠蔽と呼ぶ(ただし、baseキーワードを使えば、基底クラスのメソッドを呼び出すことはできる)。
class Base { public void Test() { Console.WriteLine("Base Test"); } } class Derived : Base { public new void Test() { Console.WriteLine("Derived Test"); } }
sealed修飾子で継承を禁止する
クラス定義時にsealed修飾子をつけて定義すると、そのクラスは継承できなくなる。
アップキャストとダウンキャスト
基底クラスの型の変数に派生クラスの型のインスタンスを渡すことをアップキャストといい、その逆をダウンキャストという(クラスツリーの上に遡るのでアップ、クラスツリーを下るのでダウン?)。アップキャストは暗黙的に行えるが、ダウンキャストは失敗する可能性があるため明示的なキャスト式が必要。
isとas
is演算子を使うことで、ある変数があるクラスにキャスト可能か調べることができる。「p is Person」の結果がtrueなら、pはPersonにキャストできる。
as演算子を使うことで、ある変数を別のクラスにキャストできる。キャストに失敗した場合、キャスト式が例外を発生させるのに対して、as演算子はnullを返す。
仮想メソッド
C#では、通常のメソッド呼び出しは静的な型によって解決される。
using System; namespace Sample { class Base { public void Test() { Console.WriteLine("Base Test"); } } class Derived : Base { public new void Test() { Console.WriteLine("Derived Test"); } } class Program { static void Main(string[] args) { Base a = new Base(); // 静的な型はBase 動的な型はBase a.Test(); Base b = new Derived(); // 静的な型はBase 動的な型はDerived b.Test(); Derived c = new Derived(); // 静的な型はDerived 動的な型はDerived c.Test(); } } }
動的な型に基づいて呼び出すメソッドを変えるには、virtual修飾子を使用する。virtual修飾子をつけたメソッドのことを仮想メソッドと呼ぶ。仮想メソッドを派生クラスで再定義することをメソッドのオーバーライドという。
using System; namespace Sample { class Base { public virtual void Test() { Console.WriteLine("Base Test"); } } class Derived : Base { public override void Test() { Console.WriteLine("Derived Test"); } } class Program { static void Main(string[] args) { Base a = new Base(); // 静的な型はBase 動的な型はBase a.Test(); Base b = new Derived(); // 静的な型はBase 動的な型はDerived b.Test(); Derived c = new Derived(); // 静的な型はDerived 動的な型はDerived c.Test(); } } }
sealed修飾子をつけることで、継承を禁止することができる。