VBAでインターフェイス
自分はVBA歴が長い方だと思いますが、VBAでインターフェイスが使えることを最近知りました。それはもうビックリして、少し感動しました。
とは言え今すぐにこれを使って何かを作るなんてことはありそうもなく、とりあえず備忘録として、試したことをまとめておきたいと思います。
インターフェイスとは
インターフェイスとは、クラスや構造体が定義するプロパティやメソッドなどのシグネチャ(メソッドの引数や戻り値の型、メソッドの名前など)のみを書いたものです。プロパティやメソッドの識別のみが目的で実装は一切ありません。インターフェイスを実装するクラスはそのインターフェイスのすべてのメンバを実装しなければなりません。
クラスモジュールで作る
まずはインターフェイス用のクラスモジュールを追加します。名前はIAnimalとしました。
とりあえず一つ、メソッドのシグネチャを以下のように書きます。アクセス修飾子はリファレンスではPublicを書くと説明されていますが、必要ないでしょう。(VB.NETやC#に合わせて)
Sub CallOut()
End Sub
簡単なんで、ついでにもう一つ別のインターフェイスも書いておきましょう。名前はIDebugとして、ここにもメソッドを一つ書きます。
Sub DebugPrint()
End Sub
次に、これら二つのインターフェイスを実装するためのCatクラスを作ります。Catクラス用のクラスモジュールを追加して、宣言セクションにImplementsキーワードに続けてインターフェイス名を書きます。
Implements IAnimal
Implements IDebug
すると、オブジェクトボックスに2つのインターフェイスが現れます。
IAnimalインターフェイスを選択すると、
IAnimal_CallOutメソッドが出現します。
- 全てのメンバが出現するわけではない(インターフェイスのクラスモジュールで一番上に書かれたものだけ)
- 全てのメンバを実装しないとエラーとなる(インターフェイスのメンバが複数の場合)
- 手書きで実装する場合、インターフェイス名とアンダースコアをメソッド名(またはプロパティ名)に付加する
- 出現したメンバのアクセス修飾子は
Privateがつく - インターフェイス側にはアクセス修飾子をつけない(リファレンスでは
publicを付けるとの説明があるが不要) - 出現したメソッドを
Publicにすればインスタンスで使用できるようになる - その場合、利用時のメソッド名は
CallOutではなくIAnimal_CallOutとなる
以下にCatクラスの簡単な実装を書いてみました。
' 実装するインターフェイスを設定する(複数のインターフェイスを設定可能)
Implements IAnimal
Implements IDebug
Private Const meow As String = "にゃー"
Public Sub Hoge()
MsgBox "Hoge - 猫ほげ", vbInformation
End Sub
Private Sub IAnimal_CallOut()
Debug.Print "CallOut - " & meow
End Sub
Private Sub IDebug_DebugPrint()
Debug.Print "DebugPrint - わたしは猫です"
End Sub
更にDogクラスも書いてみます。
Implements IAnimal
Implements IDebug
Private Const bowwow As String = "わんわん"
Public Sub Hoge()
MsgBox "Hoge - 犬ほげ", vbInformation
End Sub
Private Sub IAnimal_CallOut()
MsgBox "CallOut - " & bowwow, vbInformation
End Sub
Private Sub IDebug_DebugPrint()
Debug.Print "DebugPrint - わいは犬や"
End Sub
2つのクラスを使ってみる
準備が整ったのでモジュールを追加してインターフェイスを実装したCatクラスとDogクラスを使ってみます。
Sub x()
' 2つのクラスとコレクションの生成
Dim AnimalBox As New Collection
Dim neko As New Cat: AnimalBox.Add neko
Dim inu As New Dog: AnimalBox.Add inu
' Dim hg As IAnimal
' For Each hg In AnimalBox
' hg.Hoge
' Next
Dim pet As IAnimal
For Each pet In AnimalBox
pet.CallOut
Next
Dim dbg As IDebug
For Each dbg In AnimalBox
dbg.DebugPrint
Next
End Sub
まずは、二つのクラスのインスタンスをコレクションに追加します。
その下のコメントアウトしたFor Eachは、二つのクラスに敢えて同名でHogeメソッドを書き、ループ内で実行させてみたテストの痕跡です。
これを動作させるとどうなるか
列挙されるアイテムを受けるhg変数はIAnimal型ですが、これはエラーとなり実行できません。
続く二つのループではIAnimalインターフェイスのメンバを実装したCallOutメソッドと、IDebugインターフェイスのメンバを実装したDebugPrintメソッドを実行させています。
そして、これは問題なく実行されます![]()
コレクション内のnekoとinuは別々のクラスのインスタンスですが、同じ構文でメソッドを実行できています。正にここがキモ、ポリモーフィズムってやつですね![]()
CatクラスのCallOutではDebug.Printで「にゃー」と鳴かせていますが、DogクラスのCallOutではDebug.PrintではなくMsgBoxで鳴かせています。この様に同じCallOutでも全く違った挙動をさせることができます。
この他にもインターフェイスの効用として疎結合(クラスの変更容易性)やクラスの特性・動作をユーザーに約束する機能保証などがあります。
以下、インターフェイスについての良い説明記事がありました。
残念ながらIAnimal型のインスタンスでCatクラス(及びDogクラス)のHogeメソッドは呼び出せません。これはVB.NETであればキャストして呼び出せます。
Dim pet As IAnimal = New Cat
DirectCast(pet, Cat).Hoge()
さいごに独り言
今年は業務ツールを作る際、意識的にVB.NETを避けてC#で書いていましたが、この記事の検証のために久々にVB.NETに触れ、何とも懐かしくて胸躍りました。
やっぱりVBはええなあ、、、
![]()
![]()
![]()
![]()
![]()
![]()
追記(2024.12.13)
上述のコメントアウトしたHogeメソッドですが、Objectで受けるとエラーになりませんでした![]()
Dim hg As Object
For Each hg In AnimalBox
hg.Hoge
Next



