連載
プロフェッショナルVB.NETプログラミング
第10回 オブジェクト関連(後編)
(株)ピーデー
川俣 晶
2002/06/22
|
|
中身のないメソッドに対し、継承により中身を入れる
これまで説明したとおり、継承を行う際にメソッドの中身を入れ替えることができるが、あらかじめ中身のないメソッドを用意しておき、継承時に中身を与えることもできる。これは、インターフェイスに似た使い方といえる。
VB.NETで中身のないメソッドを記述した例を以下に示す。
1: Public MustInherit Class Class1
2: Public MustOverride Sub Test()
3: End Class
|
|
MustOverrideキーワードとMustInheritキーワードを使用して、中身のないメソッドを記述したVB.NETのサンプル・プログラム17 |
ここで注目すべき点が2つある。1つは、2行目のMustOverrideキーワードである。これは、このメソッドは必ず継承したクラスでオーバーライドしなければならいことを示している。中身がない以上当然の話ではあるが、継承により中身を与えずに使うことはできない。またもう1点は、1行目のMustInheritキーワードである。このキーワードは、そのクラスが、継承しなければならないことを意味している。
では、これを継承して、中身を与えたクラスを記述してみよう。
1: Public Class Class2
2: Inherits Class1
3: Public Overrides Sub Test()
4: Trace.WriteLine("Test in Class2 called")
5: End Sub
6: End Class
|
|
サンプル・プログラム17を継承して、メソッドの中身を記述したVB.NETのサンプル・プログラム18 |
さらににもう1つ。
1: Public Class Class3
2: Inherits Class1
3: Public Overrides Sub Test()
4: Trace.WriteLine("Test in Class3 called")
5: End Sub
6: End Class
|
|
サンプル・プログラム17を継承した別のクラスを定義したVB.NETのサンプル・プログラム19 |
これらは、OverridesキーワードをSubキーワードの前に付ける必要があるだけで、特別な構文を使用する必要はない。
では、これらを呼び出すサンプル・コードを記述してみよう。
1: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
2: Dim o2 As New Class2()
3: Dim o3 As New Class3()
4: Dim o1 As Class1
5: o2.Test()
6: o3.Test()
7: o1 = o2
8: o1.Test()
9: o1 = o3
10: o1.Test()
11: End Sub
|
|
サンプル・プログラム17と18を使用するサンプル・プログラム20 |
これを実行すると以下のようになる。
1: Test in Class2 called
2: Test in Class3 called
3: Test in Class2 called
4: Test in Class3 called
|
|
サンプル・プログラム20の実行結果 |
ここで注目していただきたい部分は、コードの7〜10行目である。Class1型の変数に代入してからメソッドTestを呼び出しても、Class2やClass3で定義した内容が実行されている。つまり、MustOverrideキーワードには、Overridableと同様の機能が含まれているということである。それに対して、MustOverrideキーワードを使わない方法に相当する機能は記述できない。仮に記述できても、中身のないメソッドを呼び出すことは無意味であるため、使い道はない。
Instancingプロパティの変更
VB 6でActiveX DLLを作成する際、クラス・モジュールのInstancingプロパティをGlobalMultiuseなどに設定することで、メイン・プログラムから、グローバルな関数であるかのようにメソッドを呼び出し可能にすることができる。
実際に実例を見てみよう。まず、“ActiveX DLL”の新規プロジェクトを作成し、以下のようなコードをクラス・モジュールに書き込む。
1: Sub Test()
2: MsgBox "Hello!"
3: End Sub
|
|
“ActiveX DLL”プロジェクトのクラス・モジュールに書き込むVB 6のサンプル・プログラム21 |
書き終えたら、InstancingプロパティをGlobalMultiuseに設定する。
できたら、[ファイル]メニューの[Project1.dllの作成]を選んで、ファイルを作成しておく。
さて、次はこれを呼び出す側のプログラムである。標準EXEのプロジェクトを新規作成してから、[プロジェクト]メニューの[参照設定]を選び、たったいま作成したActiveX DLLへの参照を追加する。そして、フォームのLoadイベントに以下のように書き込む。
1: Private Sub Form_Load()
2: Test
3: End Sub
|
|
ActiveX DLL内のメソッドを呼び出すVB 6のサンプル・プログラム22 |
これを実行すると以下のようになる。
|
サンプル・プログラム22の実行結果 |
見てのとおり、Loadイベント中では、シンプルにTestとだけ書いているが、実際にはクラスの中のメソッドであり、本来はインスタンスを明示しなければ呼び出せないものである。この場合、インスタンスは暗黙的に作成されて、それが呼び出される。
さて、VB.NETには、これに相当する機能は存在しない。その代わり、より汎用的なImportsステートメントというものを使って、似たような効果を得ることができる。Importsステートメントは、VB.NET言語仕様の一部であり、プロジェクトの種類に関係なく使用できる。ActiveX DLLのような特定の使い方に限定されない。以下は1つのプログラム内で完結するサンプル・プログラムである。
では、まず、このようなクラスがあったとしよう(作成するプロジェクト名は“Sample001n”とする)。
1: Public Class Class1
2: Public Shared Sub Test()
3: MsgBox("Hello!")
4: End Sub
5: End Class
|
|
Sharedなメソッドを含んだクラスを定義したVB.NETのサンプル・プログラム23 |
2行目にSharedキーワードがあることから分かるとおり、このメソッドはインスタンスを明示しなくても呼び出せる。しかし、インスタンスの代わりにクラスは明示しなければならないので、ただ単にTest()と書くだけでは呼び出せない。そこで、呼び出す側でImportsステートメントを使用する。以下はImportsステートメントを記述した例である。
1: Imports Sample001n.Class1
2:
3: Public Class Form1
4:
5: Inherits System.Windows.Forms.Form
6:
7: #Region " Windows フォーム デザイナで生成されたコード "
8:
9: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
10: Test()
11: End Sub
12: End Class
|
|
Importsステートメントを使用し、サンプル・プログラム23のメソッドを呼び出すサンプル・プログラム24 |
これを実行すると以下のようになる。
|
サンプル・プログラム24の実行結果 |
見てのとおり9行目で、クラス名も指定せずにTest()と書かれていて実行されている。その秘密は、1行目にある。Sample001n.Class1は、Class1の名前空間を含むフルネームに当たる(“Sample001n”はプロジェクト名から作成されるデフォルトの名前空間の名前)。このフルネームのクラスに属するものは、特にクラスを明示しなくても呼び出せるようになる。そのため、9行目のTest()は、Importsステートメントの指定により、Class1に含まれているという推理が成り立ち、呼び出せるわけである。
Importsステートメントは、クラスだけでなく、名前空間を指定することもできる。名前空間を指定するImportsステートメントがあれば、クラス名を記述する際、いちいち名前空間を含む長い名前を書かなくてもよい。
なお、Importsステートメントは複数並べて書くことも許されているので、1つに限らない。