皆さんはVBAでクラスモジュールを使っていますか?
何となく、クラスモジュールってややこしそう、使うメリットがよくわからない、など使用したことがないという方も多いように感じています。
そこで今回は、2回に分けて、クラスモジュールを使うメリットの中から、私が特に有用と感じた使い方について紹介します。
本記事では基本編である①~③のみ扱い、活用編の④は次の記事に記載します。
普段、他の言語でもクラスを使ったことがない方でもわかりやすいようにお伝えできればと思いますので、ご一読いただけると幸いです。
①はじめに
新しいファイルでは、プロジェクトエクスプローラーは下図のようにMicrosoft Excel ObjectsとしてSheet1とThisWorkbookオブジェクトのみがあります。
(古いバージョンではSheetが複数ある場合もあります)
詳細は割愛しますが、基本的に標準モジュールと同じような使い方ができます。

プロジェクトエクスプローラー内で右クリックメニューを開いて「挿入」にカーソルを乗せると、下図のように「ユーザーフォーム」、「標準モジュール」、「クラスモジュール」を追加することができます。

他の言語を扱ったことがある方は、1つのモジュールが1ファイルに相当すると考えるとイメージしやすいと思います。
②標準モジュールと何が違う?
まず、クラスモジュールというのは、標準モジュールと何が違うのでしょうか?
大きく違う点として、下記2点がすぐに思い浮かびます。
- プロパティを使用することができる
- 外部から呼び出す際はインスタンスが必要
②-1. プロパティについて
プロパティというのは、Range(“A1”).ValueのValueの部分ですね。これを自作できます。
例えば、下記のようにするとnameプロパティを持つクラスを作ることができます。
|
1 2 3 4 5 6 7 8 9 10 11 |
Option Explicit Private name_ As String Public Property Get name() As String name = name_ End Property Public Property Let name(ByVal val As String) name_ = val End Property |
ここは、私も最初は躓いた箇所なので、少し詳しく書きたいと思います。
まず、Private name_ as stringの部分ですが、ここはname_である必要はありません。ただ、プロパティ名と同じ変数名にしておくことで、後で見たときにわかりやすいので、このように定義しておくのがおすすめです。
当然、この変数name_はPrivateなので、このクラスモジュール内でのみアクセスできます。
これを外部から書き換えできるようにするのが、一番下のLetプロシージャです。所謂アクセサですね。間のGetプロシージャはその名の通り、外部から値を取得するためのアクセサとなります。
この、GetやLetの後に書かれた部分 “name” が外部からアクセスするプロパティ名になります。なお、これらは外部からアクセスする必要があるのでPublicにする必要があります。
つまり、一連の流れは下記のようになります。
- 「クラス.name = “hogehoge” 」でLetが呼ばる
- クラスモジュールのname_に”hogehoge”代入
- 「MsgBox クラス.name 」でGetが呼ばる
- クラスモジュールのnameプロパティに”hogehoge”(name_)代入
もちろん、name_に値を設定した(上記1~2)後は、クラス内のどこからでもname_の値を取得できます。(クラスが解放されるまで)
また、今回はstring型でしたが、オブジェクトを扱う場合はLetの代わりにSetを使い、代入の際にもSetステートメントが必要となります。例えば下記のようになります。
|
1 2 3 4 5 |
Private obj_ As Object Public Property Set obj(ByVal o As Object) Set obj_ = o End Property |
ちなみに、GetとLet/Setはセットで使うことが多いですが、外部からプロパティを直接設定することがない場合(読み取り専用)はLet/Setは不要だったり、必要に応じてどちらかのみ実装するというケースもあります。
プロパティを使うことで、グローバル変数を使わずにモジュール間で変数のやり取りが出来、自動メンバー表示が使えるなどのメリットがあります。
②-2. 外部からプロパティやメソッドの呼び出し
他の言語で既にクラスを扱った経験のある方にとっては当たり前のことかもしれませんが、インスタンスを生成しないと、クラス内に作成したプロパティやメソッドを呼び出すことはできません。
インスタンスは実体のことですが、1の例で紹介したクラスをTestClassというクラス名にしたとして、下記のように標準モジュールに書いただけでは動きません。
|
1 2 3 4 |
Sub test() TestClass.name = "hogehoge" Debug.Print TestClass.name End Sub |
当然といえばそうなのですが、クラス初心者はなぜこれがダメなのか、すぐにわからなかったりします。(筆者がそうでした)
クラスというのはあくまで職種のようなもので、その職種に就いている人(実体)がいないと何もできないという感じのイメージでしょうか。
動くように書き直すと下記のようになります。
|
1 2 3 4 5 6 7 8 |
Sub test() Dim hito As TestClass Set hito = New TestClass ' もしくはDim hito As New TestClass hito.name = "hogehoge" Debug.Print hito.name End Sub |
また、クラスモジュール内に下記のようなメソッド(Public)を実装したとして、これを標準モジュール(外部)からそのままCall TestClassFuncとしても呼び出せません。
|
1 2 3 |
Public Sub TestClassFunc() MsgBox "test" End Sub |
先程と同様にインスタンスが必要です。
|
1 2 3 4 5 6 7 |
Sub test() ' Call TestClassFunc ← NG Dim hito As New TestClass Call hito.TestClassFunc End Sub |
ちなみに、クラスモジュール内のPrivateプロシージャはクラスモジュール内でも普通に呼び出すことができます。
|
1 2 3 4 5 6 7 |
Public Sub TestClassFunc() Call testMsg("hogehoge") End Sub Private Sub testMsg(ByVal val As String) MsgBox val End Sub |
ここまでの話だけ聞くと、インスタンス化しないと使えないなんて手間が増えて大変だと感じるかもしれませんが、このようにオブジェクトを扱うことに慣れることでメンテナンス性や可読性の高いコードを書くことが出来るので、結果的に生産性向上に繋がります。
③実はユーザーフォームもクラスモジュールとして機能する?
これは、補足ではありますが、下記の記事にも以前書きましたが、ユーザーフォームでもプロパティが使えます。また、この後出てくるWithEventsもユーザーフォームでも使うことができます。つまり、ユーザーフォームはGUIを持ったクラスモジュールのように扱えるということですね。
以前の記事:ユーザーフォームをオブジェクト化するメリット
活用編に続く

