更新日:、 作成日:

VBA 値型と参照型の違い

はじめに

Excel VBA マクロの値型と参照型の違いを紹介します。

変数名 = 値 のように代入するのが値型です。Integer や String などがあります。

Set 変数名 = オブジェクト のように Set を付けて代入するのが参照型です。Worksheet や Range、クラスなどがあります。

値型と参照型の違いは、参照型の変数を別の変数に代入しても同じインスタンスです。そのため、どちらの変数の値を変更しても、もう一方にも反映されます。

値渡しと参照渡しについては「関数に引数を渡す」をご覧ください。

値型と参照型とは

データ型には値型と参照型があります。

値型には Integer や String や Date などがあります。変数名 = 値 のように代入できるものはすべて値型です。

参照型には Worksheet や Range、クラスで作成されたものがあります。すべてオブジェクトです。Set 変数名 = オブジェクト のように、代入に Set が必要な型はすべて参照型です。

クラスについては「クラス」をご覧ください。

値型と参照型の違い

参照型の変数を別の変数に代入したときに値型との違いがあります。Excel のセル参照を使ったことがあれば理解しやすいと思います。

次のような単純な Value 変数だけを持ったクラスで説明します。

Class1 (参照型) のコード

Public Value As Integer

Sheet1 のコード

Class1 の変数を 2 つ宣言します。

Dim c1 As Class1
Dim c2 As Class1
1

Class1 をインスタンス化します。これは新しいセルを参照するのと同じです。

Set c1 = New Class1
2

インスタンスを別の変数に代入します。これはセル参照をコピーするのと同じです。Value の値をコピーするのではなく参照をコピーする、この部分が値型と参照型の違いです。

Set c2 = c1
3

c1 の Value に値を設定します。c2 も同じセルを参照しているので、同じ値になります。

c1.Value = 10
Debug.Print(c1.Value) ' 10
Debug.Print(c2.Value) ' 10
4

c2 に新しいインスタンスを設定します。これは別のセルを参照するのと同じです。インスタンス化する度に、新しいセルを参照することになります。

Set c2 = New Class1
5

参照先が違うので c1 と c2 の Value は別の値になります。

c2.Value = 20  
Debug.Print(c1.Value) ' 10
Debug.Print(c2.Value) ' 20
6

引数に参照型を渡す

関数の引数に参照型を渡すと、インスタンスを別の変数に代入しているのと同じで、参照を渡しています。そのため、関数の中で参照型の値が変更されると渡した変数の値も変更されます。

Sub 実行()
    Dim c As Class1
    Set c = New Class1

    Call 参照型渡し(c)
    Debug.Print(c.Value) ' 10

    Set c = Nothing
End Sub

Sub 参照型渡し(ByVal c As Class1)
    c.Value = 10 ' 引数に渡した変数の Value も変更される
End Sub

まとめ

オブジェクト型の変数にはインスタンスが入っています。インスタンスとはオブジェクトの参照先です。

その変数を別の変数に代入すると、インスタンスがコピーされるので同じオブジェクトが参照されます。参照先が同じなら、どちらの変数で値を変更しても両方に反映されます。

2 つの変数で別の値を持ちたいのなら、新たにインスタンス化します。新しい参照先になるので、それぞれで別の値を持てます。

値型はそのまま値がコピーされるだけなので単純です。参照型はインスタンスを意識すると理解できると思います。