オーバーライドとは基底クラスのメソッドを派生クラスで再定義する事です。
派生クラスを作成する時、基底クラスの機能の一部をちょっと変えたいなという時に使用します。
オーバーライドを使いこなすためには「virtual」「new」「override」という3つのキーワードを理解する必要があります。
※C++でもオーバーライドの機能があり同じようにvirtualキーワードを使いますがC#とは仕様が少し異なります。
C#での動きを正しく理解して使いこなしましょう。
virtualキーワード
virtual キーワードは基底クラスで使用します。
このメソッドは派生クラスでメソッドの再定義 (override) をしても構わないですよという意味になります。
※virtual キーワードを定義せずに派生クラスで override を使おうとするとコンパイルエラーになります
public class TestBase { public virtual void Test() { System.Console.WriteLine("TestBase.Test()"); } }
new キーワード
new キーワードは派生クラスで使用します。
派生クラスでメソッドを再定義する場合「new」か「override」のどちらかを使って定義する事になりますが、どちらを使うかでメソッドの呼ばれ方が変わってきます。
- new ・・・ 変数の型によってメソッドが呼び分けられる
- override ・・・ 必ずインスタンスの型のメソッドが呼び出される
new は変数の型によって基底クラスのメソッドが呼ばれるか派生クラスのメソッドが呼ばれるかが変わります。つまり基底クラスのキャストした後にメソッドを呼び出すと基底クラスのメソッドが使われます。
基底クラスへキャストした時の例
public class TestBase { public void Test() { System.Console.WriteLine("TestBase.Test()"); } } public class TestDerived : TestBase { public new void Test() { System.Console.WriteLine("TestDerived.Test()"); } } static void Main(string[] args) { TestDerived testD = new TestDerived(); TestBase testB = testD; testD.Test(); testB.Test(); }
結果は以下の通りです。
TestDerived.Test() TestBase.Test()
「TestBase」へキャストした「testB」では基底クラスのメソッドが呼ばれる事が分かります。
クラス内からメソッドが呼ばれる例
public class TestBase { public void Test() { System.Console.WriteLine("TestBase.Test()"); } public void Call() { Test(); } } public class TestDerived : TestBase { public new void Test() { System.Console.WriteLine("TestDerived.Test()"); } } static void Main(string[] args) { TestDerived testD = new TestDerived(); TestBase testB = testD; testD.Call(); testB.Call(); }
結果は以下の通りです。
TestBase.Test() TestBase.Test()
この例では基底クラスにある Call メソッドから Test メソッドが呼び出されています。
派生クラスのインスタンスである「testD」から Callメソッドを呼び出しても基底クラスの Test メソッドが呼び出される事が確認できます。
override キーワード
override キーワードは派生クラスで使用します。
派生クラスでメソッドを再定義する場合「new」か「override」のどちらかを使って定義する事になりますが、どちらを使うかでメソッドの呼ばれ方が変わってきます。
- new ・・・ 変数の型によってメソッドが呼び分けられる
- override ・・・ 必ずインスタンスの型のメソッドが呼び出される
override はインスタンスの型のメソッドが呼ばれます。
基底クラスへキャストしたとしても、基底クラスから再定義されたメソッドが呼びだされたとしてもインスタンスを作成したクラスのメソッドが使われます。
※基底クラスで virtual キーワードを定義せずに override を使おうとするとコンパイルエラーになります
public class TestBase { public virtual void Test() { System.Console.WriteLine("TestBase.Test()"); } public void Call() { Test(); } } public class TestDerived : TestBase { public override void Test() { System.Console.WriteLine("TestDerived.Test()"); } } static void Main(string[] args) { TestDerived testD = new TestDerived(); TestBase testB = testD; testD.Test(); testB.Test(); testD.Call(); testB.Call(); }
結果は以下の通りです。
TestDerived.Test() TestDerived.Test() TestDerived.Test() TestDerived.Test()
基底クラスのメソッドを呼び出す
メソッドをオーバーライドする時、基底クラスの処理にちょこっと付け足すだけような場合は改めてコードを書き直すより基底クラスのメソッドを呼び出したいと思うかもしれません。
そんな時は base キーワードを使いましょう。
public class TestDerived : TestBase { public override void Test() { base.Test(); // ←ココ System.Console.WriteLine("TestDerived.Test()"); } }
関連記事
- C#の値型と参照型の違い
- C#のコンストラクタでオーバーロード
- C#のコンストラクタの継承
- C#のジェネリックを使おう
- C#のデリゲート (delegate) って何?
- C#のデリゲートお手軽にする匿名メソッド
- C#のラムダ式【=>】って何?
- C#で基底クラスのメソッドを置き換えるオーバーライド
- C#でキャストとas演算子を使いこなす
- C#で型を判別するtypeofとis演算子
- C#の値型でもnullを扱えるようにするNullable
- C#のリソース解放にはIDisposableとusingを使おう
- C#のStringとstring、Int32とint 違いは・・・ない!
- C#でasync/awaitを使った非同期処理
- C#で文字列を指定の区切り文字で分割
- C#のstring.Formatで桁数や書式を指定する
- C#の配列やListをソートする
- C#の配列やListを検索する (Find,FindAll,FindIndex)
- C#の配列やListを高速に検索する (BinarySearch)
- C#の配列の中に指定の要素が存在するかを調べる(LINQ Contains)
- C#の配列の中に条件を満たす要素が存在するかを調べる(LINQ Any)
- C#の配列から条件に合う要素を抽出する(LINQ Where)
- C#の配列で要素毎の処理結果を得る(LINQ Select)
- C#の配列を並び替える(LINQ OrderBy,ThenBy)
- C#の配列をグループ毎に処理する(LINQ GroupBy)
- C#の配列を内部結合(INNER JOIN)する(LINQ Join)
- C#の配列から最初の要素を取り出す(LINQ First,FirstOrDefault)
- C#の配列の重複要素を削除する(LINQ Distinct)
- C#でフォルダ内のファイル名一覧を取得する
- C#でテキストファイルを読み込む
- C#でテキストファイルに書き込む
- C#でバイナリファイルを読み込む
- C#でバイナリファイルに書き込む
コメントをお書きください