基本クラスの機能を受け継ぐだけが継承ではない。今回解説するような継承の機能こそがプログラミングでは実は重要だ。
前回の「継承を使うために知っておくべきこと」では、「継承」について、基本クラスを継承した派生クラスの記述方法を中心に解説しました。具体的にはクラス・ライブラリにあるFormクラスを継承したNewFormクラスを定義し、そのインスタンスを作成してウィンドウを開く、といったことを行いました。そのコードの中で、実は重要なポイントなのに特に解説せずにさらっと流した点が1つあります。
それは、前回の1ページ目の最後に示したサンプル・プログラムの、次のような最後の1行です。
Application.Run(myNewForm1);
ApplicationクラスのRunメソッドは第3回の「Windowsアプリケーションのメッセージ・ループ」で解説したように、Windowsのメッセージ・ループ処理を実行するためのものです。その動作については、前回の「既存メソッドを書き換える『メソッドのオーバーライド』」でも、次のような図を用いて解説しました。
上記の1行で、Application.Runメソッドのパラメータとして指定している変数myNewForm1は、次のようなコードにより宣言されたNewFormクラスのインスタンスを参照している、NewForm型の変数です。
NewForm myNewForm1;
myNewForm1 = new NewForm();
しかし、上の図1にもあるように、Application.Runメソッドのパラメータの型はForm型です。にもかかわらず、このコードではNewForm型の変数を渡しています。本来ならば、次のようなシグネチャを持ったApplication.Runメソッドが必要となるはずです。
public static void Run(NewForm form)
もちろん、NewFormクラスは自分で定義したクラスなので、そんなクラスをクラス・ライブラリにあるApplicationクラスが知るはずもなく、このようなメソッドが用意されているはずはありません。
ここに継承によってもたらされる非常に重要な仕組みが隠されています。それは、
「派生クラスのインスタンスの参照は、その基本クラスのインスタンスの参照として扱える」
ということです。あるいは次のようにいい換えることができます。
「派生クラスのオブジェクトは、その基本クラスのオブジェクトとして扱える」
これはつまり、次のような代入が許されているということになります。
Form myForm1 = myNewForm1;
ここで、変数myForm1はForm型ですが、myNewForm1はNewForm型です。第2回の「Formオブジェクト用の変数はForm型」では、「基本的に、変数の型は、その変数が参照するオブジェクトのクラスと同じ名前になります。」と解説しました。しかし継承が絡むこの場合には、変数myForm1が参照しているオブジェクトのクラスは、実際にはNewFormクラスとなります。
以上を図にすると次のようになります。
あるオブジェクトを異なる型の変数に代入するには、「キャスト」と呼ばれる明示的な型変換を行う必要がありますが、このような基本クラスの型への代入ではキャストは不要です。つまり、派生クラスの型はその基本クラスの型へ暗黙的に変換できるということになります。
なお、NewFormオブジェクトをForm型の変数に代入するということは、NewFormクラスがメソッドの追加などによりFormクラスの機能を拡張していたとしても、それを単にFormオブジェクトと見なして扱うということになります。前回で解説したとおり、NewFormクラスは継承によりFormクラスのすべてのメンバを受け継いでいるのでこれは可能です。
Application.Runメソッドに関していえば、このメソッドの仕事は、パラメータで指定されたフォーム(FormオブジェクトやNewFormオブジェクト)に対して、Windowsのメッセージを処理することです。NewFormクラスがFormクラスに対してどのような拡張を行っていたとしても、この基本的な処理は変わりません。つまりApplicationクラスのRunメソッドは、どのようなフォームであっても、そのフォームがFormクラスの派生クラスであれば、それに対応することができるのです。
Copyright© Digital Advantage Corp. All Rights Reserved.