連載
プロフェッショナルVB.NETプログラミング
第9回 オブジェクト関連(前編)
(株)ピーデー
川俣 晶
2002/06/15
|
|
コンストラクタへの引数
インスタンス内部の初期値を、インスタンスを生成する側から設定するケースを考えてみよう。例えば、名前と年齢を保持する2つの変数を持つクラス“Class1”のインスタンスを生成して利用する場合は、この2つの変数に値を設定する必要がある。VB 6では、インスタンスを生成してから、必要な値を設定するので、個別の値を設定する手段をクラスの中に用意しなければならない。以下は、プロパティ経由で値を設定する機能を含めて作成してみたクラスである。
1: Private name0 As String
2: Private age0 As Integer
3:
4: Public Property Let name(ByVal s As String)
5: name0 = s
6: End Property
7:
8: Public Property Let age(ByVal a As Integer)
9: age0 = a
10: End Property
11:
12: Public Sub OutputData()
13: Debug.Print name0
14: Debug.Print age0
15: End Sub
|
|
プロパティ経由でクラス内の変数を設定できるVB 6のサンプル・プログラム5 |
これを利用する側のコードは、以下のような感じになる。
1: Private Sub Form_Load()
2: Dim taro As New Class1
3: taro.name = "Taro"
4: taro.age = 17
5: taro.OutputData
6: End Sub
|
|
サンプル・プログラム5を利用するVB 6のサンプル・プログラム6 |
これを実行すると以下のようになる。
これをVB.NET用として書き換えてみよう。クラス内の変数への値の設定は1回限りとすれば、コンストラクタの引数を経由して値を入れてしまうことができる。そのようなクラスを記述してみたのが下記のサンプル・プログラムである。
1: Public Class Class1
2: Private name As String
3: Private age As Integer
4:
5: Public Sub OutputData()
6: Trace.WriteLine(name)
7: Trace.WriteLine(age)
8: End Sub
9:
10: Public Sub New(ByVal n As String, ByVal a As Integer)
11: name = n
12: age = a
13: End Sub
14: End Class
|
|
コンストラクタの引数によりクラス内の変数を設定するVB.NETのサンプル・プログラム7 |
このソースのNewメソッドに引数が付いていることが分かるだろう。この引数は以下のように記述することで利用できる。
1: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
2: Dim taro As New Class1("Taro", 17)
3: taro.OutputData()
4: End Sub
|
|
サンプル・プログラム7を利用するVB.NETのサンプル・プログラム8 |
これを実行すると以下のようになる。
このソースの2行目のように、As Newキーワードを使用した宣言のときに、クラス名の後に引数を記述することができる。
コンストラクタに引数を渡すのは、以下のような書式でも可能である。
1: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
2: Dim taro As Class1
3: taro = New Class1("Taro", 17)
4: taro.OutputData()
5: End Sub
|
|
コンストラクタ呼び出しを別の書式に変えたVB.NETのサンプル・プログラム9 |
インターフェイス機能の変更点
VB 6には、継承はなくてもインターフェイスの機能があり、簡単なポリモーフィズムぐらいなら記述することができた。しかし、このインターフェイス関係の機能が、VB 6とVB.NETでは大幅に変化している。この実例を見てみよう。
ここでは、クラス1個、インターフェイス1個を持つサンプル・プログラムを記述してみよう。そして、インターフェイス経由で、クラス内に記述したメソッドを呼び出してみよう。まずは、インターフェイス“Class2”を定義したソースである。
1: Public Sub OutputMessage(ByVal msg As String)
2: End Sub
|
|
インターフェイス“Class2”を定義したVB 6のサンプル・プログラム10 |
次に、このインターフェイスを実装するクラス“Class1”を記述してみた。
1: Implements Class2
2: Public Sub Class2_OutputMessage(ByVal msg As String)
3: Debug.Print msg
4: End Sub
|
|
サンプル・プログラム10のインターフェイスを実装したVB 6のサンプル・プログラム11 |
これらを利用して、インターフェイス経由でクラスのメソッドを呼び出すコードとして以下のようなものを書いてみた。
1: Private Sub Form_Load()
2: Dim obj As Class1
3: Set obj = New Class1
4: Dim interf As Class2
5: Set interf = obj
6: interf.OutputMessage "Hello!"
7: End Sub
|
|
インターフェイス経由でクラスのメソッドを呼び出すVB 6のサンプル・プログラム12 |
これを実行すると以下のような出力が得られる。そのことに疑問はないと思う。
さて、このソースをVB.NET用に書き換えるにはどうすればよいのだろうか。1つずつソースを置き換えてみよう。まず、インターフェイスの定義は以下のようになる。
1: Public Interface Class2
2: Sub OutputMessage(ByVal msg As String)
3: End Interface
|
|
インターフェイスを定義しているサンプル・プログラム10をVB.NETで書き換えたサンプル・プログラム13 |
見ての通り、相当違っていることが分かるだろう。まず、VB 6ではインターフェイスはクラスの一種として作成したが、VB.NETではインターフェイスはインターフェイスという機能として扱われている。そのため1行目のように、“Public Interface”で始めて、3行目のように“End Interface”で終わる必要がある。そして、肝心の中身の定義も大きく異なっている。VB 6では中身のないSubを記述することでインターフェイスのメンバを定義したが、VB.NETでは、最初から中身がないものとして扱われる。これは、最初に1行目でインターフェイスであることを明示していることにより、中身が存在しないことが明らかだからである。その結果、中身の終わりを示すEnd Subを記述する必要はなく、実際、上記のソースにはEnd Subが含まれない。
もう一点の相違は、Subの手前に付いていたPublicキーワードが、VB.NETでは不要になったことだ。インターフェイスでは、Privateにすることに意味がないので、Publicキーワードをわざわざ付ける意味はない。もし、インターフェイスにPrivateな定義が含まれていたとしても、それをほかのクラスなどから参照できないため、実装することができないのである。
なお、ここではVB 6のソースに合わせてClass2という名前でインターフェイスを作成しているが、VB.NETらしいネーミングとしてはそぐわない。例えばInterface2というような名前の方が適切だろう。
さて、次は、このインターフェイスを実装するクラスのサンプル・プログラムである。
1: Public Class Class1
2: Implements Class2
3: Public Sub OutputMessage(ByVal msg As String) Implements Class2.OutputMessage
4: Trace.WriteLine(msg)
5: End Sub
6: End Class
|
|
サンプル・プログラム13のインターフェイスを実装するVB.NETのサンプル・プログラム14 |
ここで注目する必要があるのは、3行目である。ここで、インターフェイスで定義されたメソッドの内容を実装している。その際、VB 6では、クラス名とメソッド名を含む独特の名前を用いて、インターフェイスの実装であることを示していた。今回のサンプルなら、インターフェイスのクラス名がClass2で、メソッド名がOutputMessageであるため、Class2_OutputMessageという名前のメソッドを記述していた。しかし、VB.NETではそのようなネーミングを使用せず、その代わりに、Implementsキーワードを使う。Implementsキーワードの後に、インターフェイス名とメソッド名をピリオド区切りで記述する。名前空間名を含む長い名前であってもよい。これにより、どのインターフェイスのどのメソッドを実装するのかが明示される。
最後にこれらのソースを呼び出す側のコードを以下に示す。
1: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
2: Dim obj As Class1
3: obj = New Class1()
4: Dim interf As Class2
5: interf = obj
6: interf.OutputMessage("Hello!")
7: End Sub
|
|
サンプル・プログラム14を利用するサンプル・プログラム15 |
これを実行すると以下のようになる。
インターフェイスの定義と実装は変わったが、利用する方法は変わってはいないことが分かるだろう。