クラスとCallByNameとポリモーフィズム(多態性)
VBAの使い方が進んでいくとクラスを使うようになっていきます。
クラスを使うようになるとオブジェクト指向という言葉に出会い、
オブジェクト指向を学んでいくとポリモーフィズム(多態性)という言葉に出会います。
メソッドの呼び出し時に、メソッドが属するオブジェクト(クラス)の種類によって呼び出し先の実装コードが選択され、処理内容が変化する性質。
このように説明されます。
単に多態性と言った場合は、
プログラミング言語の各要素(定数、変数、式、オブジェクト、関数、メソッドなど)についてそれらが複数の型に属することを許すという性質。
ということになります。
そもそも多態性とはどのようなものかを、VBAで理解することを目的とした記事になります。
そこで、関数に多態性を持たせた多態性関数について取り上げてみました。
今回は、CallByName関数を使いどのような動きになるかを説明していきます。
CallByName関数のヘルプでの説明は以下のように書かれています。
「オブジェクトのメソッドを実行するか、オブジェクトのプロパティを設定するか返します。」
何に使うものなのか、意味も良く分からない、、、ですよね。
つまり、動的(実行時)に実行するプロシージャーを切り替えられるということです。
VBAにおけるCallByName関数は、コールバックやリフレクションを実現するための関数とも言えます。
リフレクション(reflection)
VBAで動的(実行時)に実行するプロシージャーを切り替える方法としては、
Application.RunメソッドやApplication.OnTimeメソッドもありますが、
今回はCallByName関数の文法から入り、多態性関数へと進めていきます。
CallByName関数
引数 | 内容 | |||||||||||||||
object | 必ず指定します。 バリアント型およびオブジェクト型のいずれかを指定できます。 この関数の実行対象となるオブジェクトの名前を指定します。 |
|||||||||||||||
procname | 必ず指定します。 バリアント型および文字列型のいずれかを指定できます。 オブジェクトのプロパティ名およびメソッド名を含む文字列式を指定します。 |
|||||||||||||||
calltype | 必ず指定します。 定数値を指定します。 呼び出されるプロシージャの種類を表すvbCallTypeのメンバを指定します。
|
|||||||||||||||
args() | 省略可能です。 バリアント型および配列を指定できます。 |
戻り値は、実行したメソッドまたはプロパティの取得値になります。
クラスとCallByNameとポリモーフィズム(多態性)のVBAコード
文字列型の場合、第1引数の文字を第2引数分繰り返します。
数値型(各種あり)の場合、第1引数に第2引数を掛け算します。
いずれも、第1引数のデータ型で戻します。
クラス:clsFunc
Option Explicit
Public Function Multi(ByVal arg1 As Variant, ByVal arg2 As Variant) As
Variant
On Error Resume Next '未設定のデータ型の対応
Multi = CallByName(Me, "Multi_" & TypeName(arg1), VbMethod, arg1, arg2)
End Function
Public Function Multi_String(ByVal arg1 As Variant, ByVal arg2 As Integer)
As String
Multi_String = WorksheetFunction.Rept(arg1, arg2)
End Function
Public Function Multi_Integer(ByVal arg1 As Variant, ByVal arg2 As Long) As Integer
Multi_Integer = arg1 * arg2
End Function
Public Function Multi_Long(ByVal arg1 As Variant, ByVal arg2 As Long) As Long
Multi_Long = arg1 * arg2
End Function
Public Function Multi_Single(ByVal arg1 As Variant, ByVal arg2 As Long) As Single
Multi_Single = arg1 * arg2
End Function
Public Function Multi_Double(ByVal arg1 As Variant, ByVal arg2 As Long) As Double
Multi_Double = arg1 * arg2
End Function
Public Function Multi_Currency(ByVal arg1 As Variant, ByVal arg2 As Long)
As Currency
Multi_Currency = arg1 * arg2
End Function
標準モジュール
Option Explicit
Sub sample1()
Dim rtn As Variant
Dim var As Variant
var = "123" '文字列型
rtn = Multi(var, 3)
Debug.Print TypeName(rtn), rtn
var = 123 '整数型
rtn = Multi(var, 3)
Debug.Print TypeName(rtn), rtn
var = 123& '長整数型
rtn = Multi(var, 3)
Debug.Print TypeName(rtn), rtn
var = 1234.543! '単精度浮動小数点型
rtn = Multi(var, 3)
Debug.Print TypeName(rtn), rtn
var = 1234.54321 '倍精度浮動小数点型
rtn = Multi(var, 3)
Debug.Print TypeName(rtn), rtn
var = 1234.5432@ '通貨型
rtn = Multi(var, 3)
Debug.Print TypeName(rtn), rtn
End Sub
Public Function Multi(ByVal arg1 As Variant, ByVal arg2 As Variant) As Variant
On Error Resume Next '未設定のデータ型の対応
Multi = CallByName(New clsFunc, "Multi", VbMethod, arg1, arg2)
End Function
Function Multiについては、以下のよう書くこともできます。
Public Function Multi(ByVal arg1 As Variant, ByVal arg2 As Variant) As
Variant
On Error Resume Next '未設定のデータ型の対応
Multi = CallByName(New clsFunc, "Multi_" & TypeName(arg1), VbMethod, arg1, arg2)
End Function
さらに、先にクラスのインスタンスを作成するように書くこともできます。
Sub sample1()
Dim rtn As Variant
Dim var As Variant
Dim fnc As New clsFunc
var = "123"
rtn = fnc.Multi(var, 3)
Debug.Print TypeName(rtn), rtn
var = 123
rtn = fnc.Multi(var, 3)
Debug.Print TypeName(rtn), rtn
'・・・
End Sub
いずれも書き方の違いであり、実行結果とどれも同じになります。

ステップイン(F8)で動作を確認してみましょう。
文章で説明するより、実際に動かして、その挙動を確認してみるのが一番理解が進むはずです。
実際に動作する関数は別々のものが実行されていることを確認してください。
Multi_String~Multi_Currency
これらを全てFunction Multiとだけ書けば良いということになります。
Sub sample1()
Dim rtn As Variant
Dim var As Variant
var = "123" '文字列型
rtn = Multi(var, 3)
Debug.Print TypeName(rtn), rtn
var = 123 '整数型
rtn = Multi(var, 3)
Debug.Print TypeName(rtn), rtn
'・・・
End Sub
Public Function Multi(ByVal arg1 As Variant, ByVal arg2 As Integer) As String
Multi_String = WorksheetFunction.Rept(arg1, arg2)
End Function
Public Function Multi(ByVal arg1 As Variant, ByVal arg2 As Long) As Integer
Multi_Integer = arg1 * arg2
End Function
'・・・
オブジェクト(クラス)も動的に変更すると
(VBAコード全てをコピーして、ThisWorkbookに貼り付けてください。)
Option Explicit
Sub sample2()
Dim obj As Object
Dim rtn As Variant
Dim var As Variant
Set obj = New clsFunc
var = "123" '文字列型
rtn = Multi(obj, var, 3)
Debug.Print TypeName(rtn), rtn
Set obj = ThisWorkbook
var = 123 '整数型
rtn = Multi(obj, var, 3)
Debug.Print TypeName(rtn), rtn
'・・・
End Sub
Public Function Multi(ByVal obj As Object, ByVal arg1 As Variant, ByVal
arg2 As Variant) As Variant
On Error Resume Next '未設定のデータ型の対応
Multi = CallByName(obj, "Multi", VbMethod, arg1, arg2)
End Function
Set obj = New clsFunc
Set obj = ThisWorkbook
上では事前にSetしましたが、この部分をFunction Multiの中で切り替えるようにするとより動的な感じになるでしょう。
普通なら、クラスを複数作って切り替えるということになるでしょう。
Implementsステートメント(インターフェイス)を使うことになりますが、その説明はまたの機会に。
最後に
(ただし遅いといっても、直接メソッド等を実行する場合に比べてということです。)
また今回の多態性関数の場合は、余程多くの関数を作るという場合でも無い限り、
Select Caseで分岐すれば良いだけのことなのは言うまでもないでしょう。
完成したVBAのテストツールのようなものを作るときに使うとか、
プロパティの一覧がシートにあって、その一覧にプロパティ値を出力したいとか、
実務として使う必要が出てくるとしたら、こういう場合くらいではないかと思います。
あくまで多態性の必要性・便利さを少しでも理解してもらうための入り口としての記事になります。
従いまして、あまり細かいことにこだわる必要はなく、
オブジェクトのメソッド・プロパティを文字列で指定して実行できるCallByName関数があるということと、
多態性とはどういうことなのかをざっくりと理解するだけで良いでしょう。
同じテーマ「VBAクラス入門」の記事
VBAクラスの作り方:列名のプロパティを自動作成する
VBAクラスの作り方:独自Rangeっぽいものを作ってみた
クラスとイベントとマルチプロセス並列処理
クラスとCallByNameとポリモーフィズム(多態性)
オートフィルターを退避回復するVBAクラス
オートフィルター退避回復クラスを複数シート対応させるVBAクラス
コレクション(Collection)の並べ替え(Sort)に対応するクラス
VBAクラスのAttributeについて(既定メンバーとFor Each)
VBAクラスを使ったイベント作成(Event,RaiseEvent,WithEvents)
VBAで音楽再生するクラスを作成
VBAクラスを使ったイベント作成(Event,RaiseEvent,WithEvents)
新着記事NEW ・・・新着記事一覧を見る
シート関数のCOUNTIFS,SUMIFS,MAXIFSと同じ処理|Power Query(M言語)入門(2023-02-28)
新旧マスタの差異比較|Power Query(M言語)入門(2023-02-28)
有効な最新単価の取得|Power Query(M言語)入門(2023-02-26)
有効な最新単価の取得|Power Query(M言語)入門(2023-02-21)
グルーブ内の最小・最大|Power Query(M言語)入門(2023-02-17)
2つのテーブルのマージ|Power Query(M言語)入門(2023-02-15)
「売上」が数値の行のみ取り込む|Power Query(M言語)入門(2023-02-13)
A列のヘッダー名を変更する|Power Query(M言語)入門(2023-02-11)
CSVのA列が日付の行だけを取り込む|Power Query(M言語)入門(2023-02-10)
列数不定のCSVの取り込み|Power Query(M言語)入門(2023-02-09)
アクセスランキング ・・・ ランキング一覧を見る
1.最終行の取得(End,Rows.Count)|VBA入門
2.RangeとCellsの使い方|VBA入門
3.変数宣言のDimとデータ型|VBA入門
4.繰り返し処理(For Next)|VBA入門
5.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門
6.マクロって何?VBAって何?|VBA入門
7.並べ替え(Sort)|VBA入門
8.エクセルVBAでのシート指定方法|VBA技術解説
9.Range以外の指定方法(Cells,Rows,Columns)|VBA入門
10.ブックを閉じる・保存(Close,Save,SaveAs)|VBA入門
このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。
記述には細心の注意をしたつもりですが、
間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。
掲載のVBAコードは動作を保証するものではなく、あくまでVBA学習のサンプルとして掲載しています。
掲載のVBAコードは自己責任でご使用ください。万一データ破損等の損害が発生しても責任は負いません。