継承を使うとき、頭に入れておきたいのが「既にある機能の改変」の方法です。継承は、基本的に「既にある機能をそのまま受け継ぎ、更に機能を付け足していく」といった形でどんどん拡張をしていくことができます。しかし、同じような機能を新たにまた追加していくのはちょっとわかりにくいですね。
例えば先のサンプルでは、
EnchancedMyObjectの内容を出力するのに
printDataEnchancedというメソッドを追加しました。それよりも、
MyObjectにあった
printDataを
EnchancedMyObjectで書き替えて変更することができればそのほうがスマートですね。
こうした「基本クラスにあるメソッドを派生クラスで修正する」というのに用いられるのが「
オーバーライド」という機能です。
オーバーライドとは、基本クラスにあるメソッドと同じものをサブクラスに用意することで、そのメソッドを上書きする機能です。これは以下のように記述します。
・オーバーライドされるメソッドの書き方[publicなど] virtual メソッド( 引数 ){……略……}
・オーバーライドの書き方(1)[publicなど] override メソッド( 引数 ){……略……}
・オーバーライドの書き方(2)[publicなど] new メソッド( 引数 ){……略……}
オーバーライドの基本は「
virtual」と「
override」です。基本クラス側の、オーバーライドされるメソッドに「
virtual」をつけ、「このメソッドはオーバーライドできます」ということを指定します。
virtualをつけたメソッドは「
仮想メソッド」と呼ばれ、派生クラスで上書きできるようになります。
そして派生クラス側では、同じ名前(引数、返値なども同じ)のメソッドを用意し、「
override」を指定して「このメソッドは基本クラスのメソッドをオーバーライドするものです」ということを指定します。これにより、そのメソッドが上書きされます。
overrideや
virtualを付けずに同じメソッドを派生クラス側で上書きした場合、コンパイル時に警告が表示されるようになります(警告するだけでプログラムそのものはコンパイルできちゃんと実行することはできます)。オーバーライドは、基本クラスのメソッドを上書きして機能を変えてしまいますので、このようにオーバーライドを「する側」と「される側」にきちんと指定をしておくようになっています。
また、
overrideの他に「
new」というものを指定してメソッドを記述することもできます。これはそのメソッドを基本クラスのメソッドとは別のメソッドとして追加するものです。(両者の違いについては微妙なので次に説明します)
では、簡単な例を挙げておきましょう。下のリストは、
MyObjectを継承した
EnchancedMyObjectで、基本クラスの
printDataをオーバーライドするものです。
new EnchancedMyObjectで作成されたインスタンスの
printDataを呼び出すと、オーバーライドされた
printDataが実行され、出力される内容が少し変わることがわかるでしょう。
using System;
namespace myapp
{
class Program
{
public static void Main(string[] args)
{
EnchancedMyObject obj = new EnchancedMyObject();
obj.name = "つやの";
obj.age = 123;
obj.mail = "syoda@tuyano.com";
obj.printData();
Console.ReadKey(); // キーを押すまで待つ
}
}
class MyObject
{
public string name = "(noname)";
public int age = 0;
public virtual void printData()
{
Console.WriteLine("名前:{0}, 年齢:{1}歳", name, age);
}
}
class EnchancedMyObject : MyObject
{
public string mail = "(no mail)";
public override void printData()
{
Console.WriteLine("名前:{0}, 年齢:{1}歳, メール:{2}.", name, age, mail);
}
}
}