前回の記事が長すぎたので、良きところで分割してみました。
【VBA】クラスの作り方を整理してみた(移行手順編) - ゆるおたノート
クラス
意味
今回のメイン。
「Aというオブジェクトは、BプロパティやCメソッドを持っている」といったオブジェクトの定義を行う。
本やWebページでは、「設計書」や「鋳型」と説明されていることが多い。
VBAでは、クラスモジュールを使ってユーザー自身が新しいクラスを作成できる。
インスタンス
実際にクラスを利用する時は、下記どちらかの段階でNew
キーワード*1を使って「クラス(=設計図)からオブジェクト(=実体)を生成」する。
Dim
ステートメント等を使った変数の宣言- 参照値の代入
この生成されたオブジェクトのことをインスタンスと呼ぶ。
モジュール
処理の集まり。
VBAでは、標準モジュール、クラスモジュール、シートモジュール等がある。
今回は「クラスモジュール」にクラスの設計を記入していく。
スコープ
データを参照可能な範囲。「●●
の中ならアクセスOK」の●●
の部分。
プライベートとか、パブリックとか、グローバルとかを使って、「~~レベル」と呼ばれる。
過去記事に、掲載当時に私が理解していた範囲でまとめています。
プロパティ
インスタンスの内容や状態に関する情報*2。多くは「属性」と訳される。
VBAでは、ブックの名前やセルの値、場所、オブジェクトの参照値、など。
情報をインスタンス自身に持たせて、「●●
の値を取得する」という時や「値を設定する」といった時に使う。
スコープをPublic
にすることで、外のモジュールからインスタンス.プロパティ名
で呼び出せるようになる。
プロシージャで定義する場合、使用するプロシージャは機能別にGet
とLet
/Set
の3種類に分かれている。
名前は「大文字始まり」の名詞が多い(気がする)。
値を取得する
Property Getプロシージャ
プロパティの値を返すことのみ出来る。
VBAの仕様上、Property Getプロシージャ
内で直接「プロパティへの代入・設定」することはできないので、「変数や定数を経由」して値を設定する必要がある。
使用例
'[クラスモジュール] Exampleクラス Private 仮変数 As 型 Property Get プロパティ名()As 型 仮変数 = 123 プロパティ名 = 仮変数 End Sub
'[標準モジュール] Sub test() Dim ex As New Example 'インスタンスexのプロパティの中身を確認 Debug.Print ex.プロパティ名 '「123」と表示される End Sub
値を代入する
Property Letプロシージャ
プロパティに値を設定するためのプロシージャ。
値を代入するときのLet
キーワード*3が入っている。
使用例
'[クラスモジュール] Exampleクラス Private 仮変数 As 型 Property Let プロパティ名(仮引数 As 型) 仮変数 = 仮引数 End Sub
'[標準モジュール] Sub test() Dim ex As New Example ex.プロパティ名 = 123 'プロパティに値を代入 End Sub
Property Setプロシージャ
参照するオブジェクトをプロパティに設定するためのプロシージャ。
Subプロシージャ等でオブジェクトを代入するときのSet
と同じ。
使用例
'[クラスモジュール] Exampleクラス Private 仮変数 As オブジェクト系の型 Property Set プロパティ名(仮引数 As オブジェクト系の型) Set 仮変数 = 仮引数 End Sub
'[標準モジュール] Sub test() Dim ex As New Example 'プロパティにオブジェクトの参照値を代入 Set ex.プロパティ名 = オブジェクト End Sub
引数の正しい使い方?
リファレンスによると、同じ名前のプロパティプロシージャは、引数名とデータ型をほぼ同じにしなければならないらしい。
The first argument through the next to last argument (1, …, n) must share the same names and data types in all property procedures with the same name.
同じ名前のPropertyプロシージャ間では、最初の引数~最後から2番目の引数は、同じ引数名とデータ型を共有していなければならない。
ただ、そうなっているクラスをあまり見たことがない気が。
…初心者の私が知っている限りでは。
「実際はどちらでも良い(ことにしてある)」ってことなのかな…?
<2019/10/15追記>
前回記事のコメントにて、imihito(id:imihito)さんより下記補足いただきました。
ありがとうございます!
VBAでも常に守られています(条件を満たさないPropertyを作成するとコンパイルエラーになります)。
Property Get
の返り値は、Property Set/Let
の最後の引数と同じ型にする必要がありますし、
Property Get
の引数は、Property Set/Let
の最後から1個前の引数までと、名前・型が一致する必要があります(Getに引数が無ければ、Set/Letの引数はGetの返り値と同じ型の1個のみ)前回の記事のコメント欄より
個人的には、最後の1文が重要そうです!
メソッド
命令。
Subプロシージャ
やFunctionプロシージャ
が使える。
名前は「大文字始まり」で、「●●する」のように動詞にすることが多い(気がする)。
スコープをPublic
にすることで、外のモジュールからインスタンス.メソッド名
で呼び出せるようになる。
'[クラスモジュール(Exampleクラス)] Sub メソッド名(仮引数 As 型) '処理 End Sub
'[標準モジュール] Sub 使用例() Dim ex As New Example ex.メソッド名 引数 'メソッドの呼び出し End Sub
引数を「省略可」にするには…?
VBAでは、引数の初期値には定数(もしくは定数式)しか指定できない。
ということは、Optional
な引数にプロパティの値を指定したい時は一工夫が必要そう…(調べ中)
いま頭にあるのは、下記の2つ。
- プロパティ用の値を変数ではなくモジュールレベルの定数で定義する
- プロシージャの中で引数の有無を判定して値を設定する
→ 数値だと初期値が0
なので少し面倒かも…
あとがき
ついつい適当な憶測で書いてしまうので、記事をアップする時はこんな弱小ブログでも変な認識・知識を広めちゃったりしないか毎回結構ドキドキです…
でも、今回VBAブロガーの方々に色々ご指摘いただけて嬉しいです。とっても勉強になります!
私の頭で全部理解できてるかと言ったら微妙ですが、精進します!!
…自分でも、もっとよく調べてから書かないとですね。
このシリーズについて
初心者の頭でVBAでクラスを作成する方法の整理に挑戦しています。
連載目次
- オブジェクト指向って、なんだ? - ゆるおたノート
- 【VBA】クラスの作り方を整理してみた(移行手順編) - ゆるおたノート
- 当記事【VBA】クラスの作り方を整理してみた(基本用語編) - ゆるおたノート
注釈
*1:<2019/10/14追記>
当初「Newステートメント」と書いていましたが、「Newキーワード」の誤りでした。誤解を招く表現、大変失礼いたしました…
▼参考
- 変数と定数のキーワード サマリー | Microsoft Docs
- キーワード (Visual Basic for Applications) | Microsoft Docs
- ステートメント | Microsoft Docs
そして、ご指摘頂いたチン☆テクラ(id:akashi_keirin)さん・鵜原パソコンソフト研究所さん、ありがとうございます!
*2:テレビゲームで言うところの火属性とか、ステータス異常とか、能力値とか。
*3:本来は変数などに代入する時も必要だけど、普段は省略しても動くように作られているらしい。