IT系/VBA/基本/虎の巻/クラス編

Last-modified: 2020-06-30 (火) 00:52:35

目次


概要

VBAの虎の巻クラス編。になればよいけどリンク集。

クラス

クラスモジュールを追加する

  • 「プロジェクトウィンドウ」で対象のマクロを右クリックし、「挿入」→「クラスモジュール」を選択する。
  • クラスはデフォルトでは Class1 のような名前になる。
  • 名前を変更する場合は、「プロパティウィンドウ」を表示して、「オブジェクト名」で指定する。

インスタンスを生成する

Public Sub procedure()
    Dim mine As New MyClass
    Set mine = New MyClass
End Sub

インスタンスを生成する方法は、以下のいずれかがある。

  • Dim で宣言するときに、 As New <クラスモジュール名> とする。
  • 変数に代入するときに New <クラスモジュール名> とする。

コンストラクタ

Class_Initialize、Class_Terminate という名前のプロシージャを宣言することで、インスタンス生成時と削除時に処理を挟むことができる。

' MyClassクラス
Option Explicit
'
Private Sub Class_Initialize()
    Debug.Print "initialize"
End Sub
'
Private Sub Class_Terminate()
    Debug.Print "terminate"
End Sub
' 標準モジュール
Public Sub procedure()
    Dim mine As MyClass
    Set mine = New MyClass
End Sub
' イミディエイトウィンドウで実行
Sheet1.procedure
initialize
terminate

制約

コンストラクタに引数を宣言できない

妥協策としては、

  • init のようなプロシージャを作り、インスタンス生成後に実行させる。
  • 標準モジュールにファクトリ用のプロシージャを定義する。
  • 以下のような方法もある。
    ' IConstructorクラス
    Public Function Instancing(ByVal Args As Variant) As IConstructor: End Function
    ' Class1クラス
    Implements IConstructor
    Private msg As String
    ' コンストラクタ
    Private Function IConstructor_Instancing(ByVal Args As Variant) As IConstructor
        Set IConstructor_Instancing = Me
        msg = Args(0)
    End Function
    '
    Public Sub Method1()
        MsgBox msg
    End Sub
    ' 標準モジュール
    Public Function Constructor(ClassObject As IConstructor, ParamArray Args() As Variant) As IConstructor
        Set Constructor = ClassObject.Instancing(Args)
    End Function
    ' テスト実行
    Public Sub Test()
        Dim c1 As Class1
        Set c1 = Constructor(New Class1, “これはテスト”)
        '
        c1.Method1
    End Sub

Dim で宣言するときに New しているだけでは実行されない

  • Dim の宣言と同時に New した場合、その時点では Class_Initialize は呼ばれない。
  • Class_Initialize が実行されるのは、最初にそのインスタンスが使用されるときなので注意。

静的メンバーは定義できない

VBA のクラスモジュールには、静的な変数やプロシージャを定義できない。
静的なプロシージャなどは、標準モジュールに定義しなければならない。

自分のメンバーにアクセスする

Me.<メンバー> で、自分のメンバーにアクセスできる。
ただし、この方法でアクセスできるメンバーは、可視性が Public で宣言されている必要がある。
Private なメンバーにアクセスする場合は、 Me は使えない。

' MyClass
Option Explicit
'
Public Name As String
'
Public Sub Introduce()
    Debug.Print "My name is " & Me.Name & "."
End Sub
' 標準モジュール
Public Sub procedure()
    Dim mine As New MyClass
    mine.Name = "Taro"
    mine.Introduce
End Sub
' イミディエイトウィンドウで実行
Sheet1.procedure
My name is Taro.

プロパティを定義する

Public Property Let <プロパティ名>(引数) で書き込み用のプロパティを、
Public Property Get <プロパティ名>() As <型> で読み取り用のプロパティを宣言できる。
プロパティは、 <変数名>.<プロパティ名> でアクセスできるようになる。

' MyClass
Option Explicit
'
Private My_Age As Integer
' 書込み用プロパティ
Public Property Let Age(In_Age As Integer)
    My_Age = In_Age
End Property
' 読取り用プロパティ
Public Property Get Age() As Integer
    Age = My_Age
End Property
' 標準モジュール
Public Sub procedure()
    Dim mine As New MyClass
    mine.Age = 17
    Debug.Print mine.Age
End Sub
' イミディエイトウィンドウで実行
Sheet1.procedure
17

インターフェース

VBA では、インターフェースを定義したポリモーフィズムを利用できる。

インターフェースの実装

インターフェースの定義は、クラスモジュールで行う(MyInterface)。
インターフェースには、実装が空っぽのプロシージャ定義だけを記載する。

' MyInterface クラス
Public Sub Method()
End Sub

インターフェースを実装するときは、まずクラスモジュールの先頭で Implements <実装するインターフェース> と記述する。
次に、インターフェースで定義されたメソッドの具体的な実装を記述する。
この時、実装するメソッドの名前にはプレフィックスとして <インターフェースの名前>_ を追加する(MyInterface_Method)。

' Hoge クラス
Implements MyInterface
'
Public Sub MyInterface_Method()
    Debug.Print "Hoge Method"
End Sub
' Fuga クラス
Implements MyInterface
'
Public Sub MyInterface_Method()
    Debug.Print "Fuga Method"
End Sub
' Module1 モジュール
Public Sub Execute()
    Dim HogeInstance As MyInterface
    Dim FugaInstance As MyInterface
    Set HogeInstance = New Hoge
    Set FugaInstance = New Fuga
    HogeInstance.Method
    FugaInstance.Method
End Sub
' Module1.Execute プロシージャを実行する。
'イミディエイトウィンドウ出力
Hoge Method
Fuga Method

ダウンキャスト

上述のインターフェース実装で作成した Hoge と Fuga のインスタンスは、 MyInterface 型の変数として定義されている。
これをダウンキャストして、 Hoge 型の変数に代入するには以下のようにする。

Public Sub Execute()
    Dim Instance As MyInterface
    Set Instance = New Hoge
    '
    Dim HogeInstance As Hoge
    Set HogeInstance = Instance ' ダウンキャスト
    '
    HogeInstance.MyInterface_Method
End Sub
' 実行結果
Hoge Method

普通にダウンキャスト後の型の変数に代入すればいい。

For Each に対応する

対応させたいクラスをエクスポートして、以下の記述を追加。

Private col As Collection
'
Public Property Get NewEnum() As IUnknown
Attribute NewEnum.VB_UserMemId = -4
    Set NewEnum = col.[_NewEnum]
End Property

「Attribute NewEnum.VB_UserMemId = -4」はエクスポートしないと追加できない。
追加後、インポートする。

インターフェースで対応

「Attribute NewEnum.VB_UserMemId = -4」をインタフェースに仕込んでおくことで、一々クラス毎にエクスポート・インポートの手順を踏まずに済む。

Public Property Get NewEnum() As IUnknown
Attribute NewEnum.VB_UserMemId = -4
End Property

既定のメンバを設定

設定したいクラスをエクスポートして、既定のメンバにしたい Function や Property に「Attribute <メンバ名>.VB_UserMemId = 0」の記述を追加。

Public Function Hoge() As Boolean
Attribute Hoge.VB_UserMemId = 0
    ' 処理
End Function

「Attribute <メンバ名>.VB_UserMemId = 0」はエクスポートしないと追加できない。
追加後、インポートする。

リンク集

重複を恐れないリンク集。

総合学習

チートシート

その他メモ