プロパティ

 VB でプログラミングする際、何気なく使っているオブジェクトのプロパティ。
プロパティとは、オブジェクトの状態を表す値(変数)です。

ただし、プロパティは単なる変数ではありません。
プロパティに値を設定することで、オブジェクトの外見が変わったりすることがあります。(たとえば、フォームの Caption プロパティの文字列を変更すると、ウィンドウタイトルが変更されますね。)また、値の取得(参照)だけを許し、書き込みができないものもあります。

ここでは、そんなプロパティの性質や実装方法を見てゆきます。

構造体をクラスに発展させる

 構造体をクラスに発展させる場合、構造体の各データがオブジェクトのプロパティになります。

'構造体(変数)の内容を操作
With chaHero 'As CharacterType
    .Name = "Somebody"
    .Level = 1
    .HP = 200
    .MP = 0
End With
'クラス(オブジェクト)のプロパティを操作
With chaHero 'As CharacterClass
    .Name = "Somebody"
    .Level = 1
    .HP = 200
    .MP = 0
End With

クラスを利用する際のコードを見る限り、何も変わりません。
しかし、クラスにプロパティを実装させることは、構造体を定義するように簡単ではありません。

値の取得と設定

 プロパティの立場に立って考えると、プロパティの値は「取得」されるときと「設定」されるときがあります。

Private Sub txtWindowTitle_Change()
    
    Caption = txtWindowTitle.Text
    
End Sub

フォームに txtWindowTitle という TextBox があるとします。

txtWindowTitle の Text プロパティの値が変更されると、Change イベントが発生し、イベントプロシージャが呼び出されます。

イベントプロシージャでは、フォームの Caption プロパティに、入力された値(文字列)を代入しています。実行すると、フォームのウィンドウタイトル(キャプション)が、テクストボックスに入力した文字列になります。

ここでは、Caption プロパティの値は「設定」され、Text プロパティの値は「取得」されています。

ひとすじなわではないプロパティ

 どうやら、プロパティは、単なる変数ではなさそうです。
プロパティ値の変更と共にクラスの他の部分が変化したり、値の変更を許さないプロパティも存在します。

つまり、クラス内部では、プロパティ値の設定や取得を監視していて、状況に応じて裏で対応する操作をしているのです。

プロパティプロシージャ

 クラスにプロパティを追加する場合は、「プロパティプロシージャ」という特別専用のプロシージャを、クラスモジュールに記述します。

具体的には、Property Get と Proerty Let(Set) というプロパティプロシージャがあり、これらをセットで扱います。

Public Property Get propertyname() As type
    
End Property
Public Property Let propertyname([ByVal|ByRef] newvalue As type)
    
End Property

これは、プロパティプロシージャのプロトタイプで、propertyname には「プロパティ名」を、type には「プロパティ値の型」を指定します。クラスにプロパティを追加したい場合は、この構文でプロパティプロシージャのセットを用意します。

プロパティプロシージャは、クラス内部で「イベントプロシージャ」のように働きます。(イベントプロシージャとは、イベントが発生したときに呼び出され、実行されるプロシージャのことです。)

Property Get プロシージャは、そのプロパティに対して、外部から「値の取得」が発生したときに呼び出されます。Property Let(Set) は、外部から「値の設定」が発生したときに呼び出されます。

    variable = object.property

これは、Property Get が呼び出される場合です。
左辺の変数にプロパティ値が渡される、つまり取得されるときです。

    object.property = newvalue

一方、こちらは Property Let が呼び出される構文です。
プロパティ値を、newvalue の値に変更しようとしています。

以下に例として、Name というプロパティを記述してみます。

Public Property Get Name() As String
    
End Property
Public Property Let Name(ByVal NewValue As String)
    
End Property

プロパティ値の保存

 しかし、プロパティプロシージャを用意しただけでは、プロパティの外見を用意しただけで、実際にプロパティとしては動作してくれません。

「プロパティ値」というのですから、元を調べれば、プロパティの実体も「変数」です。当然、クラスモジュールの内部のどこかに、プロパティ値を保存しておく変数を用意するのですが、通常これは、「モジュールレベル変数」として、モジュールの先頭に宣言されます。

Option Explicit

Private m_propertyname As type

モジュールレベルでの変数(プロパティ変数)の宣言です。
プロパティ変数の名前は、プロパティ名と同じにするのが一般的です。type も、プロパティの型と同じですね。

つまり、これがプロパティの実体なのです。
Private スコープで宣言していることに注意してください。

m_ は、変数がモジュールレベルであることを示すプリフィックスです。変数名は自由に付けられますが、一般的に「m_ + プロパティ名」にします。

次のコードは、先ほどの Name プロパティのプロパティ変数の宣言例です。

Option Explicit

Private m_strName As String

プロパティ変数とプロパティプロシージャのリンク

 値を保存しておく変数とプロパティプロシージャとを結び付けなければなりません。

基本的に、
取得要求のときは、変数を返してあげます。
設定要求のときは、変数の値を変更します。

    variable = object.property
Public Property Get Name() As String
    
    Name = m_strName
    
End Property

Property Get プロシージャは、通常の Function プロシージャと同じです。戻り値として返した値が、左辺の変数に代入されます。プロパティ変数の値を返します。

    object.property = newvalue
Public Property Let Name(ByVal NewValue As String)
    
    m_strName = NewValue
    
End Property

Property Let(Set) プロシージャは、Sub プロシージャと同じ仕組みです。戻り値はなく、代わりに引数を取ります。この引数には、指定された新しい値(右辺)が代入されるので、プロパティ変数にこれを反映します。


内部変数とプロシージャをリンクさせることで、プロパティが正常に動作します。プロシージャ名(Name)と型(String)が一致することで 2 つのプロシージャがセットと見なされ、ひとつのプロパティが追加されるのです。

ここで、Property Let プロシージャを削除すると、Name プロパティは、「値の取得専用」になります。プロパティプロシージャは、「呼び出される」という形で、プロパティ値の制御を行う仕組みになっているのでした。

2000年 8月10日(木) 更新