2 つの言葉「オブジェクト」と「インスタンス」は、よくごっちゃになって使われます。何がオブジェクトで、何がインスタンスなのでしょうか。
Dim obj As Personこの変数 obj を「オブジェクト」と呼ぶことがあります。
オブジェクト変数 = オブジェクトと考えても良いでしょう。
ただし、この変数は単なる器でしかなく、「インスタンス」を格納しない限り、オブジェクトとして機能しません。
このインスタンスというのは、オブジェクトの実体でありながら、目に見えない(ソースコードの中に現れない)ので、最初は戸惑うかもしれません。
Set obj = New PersonNew Person とすると、Person 型のインスタンスが新しく生成されて obj に格納されます。
Set obj = Nothingこうすると、Nothing の代入で、obj に入っていたインスタンスは破棄されます。
Set obj = otherこうすると、obj には other のインスタンスが格納されます。other の方は空になるのか、というとそうでもなく、元々 other にあったインスタンスを参照する形で、other オブジェクトを操作することができます。これはさながら、ファイルのショートカットを作成するような感覚です。
Set obj = Nothingother インスタンスを入れたあとでこのようにすると、ショートカットである obj のインスタンスは破棄されます。しかし、other の方は破棄されません。ショートカットを削除しただけです。
サブルーチンの引数を ByVal 指定すると、その変数は「値渡し」され、呼び出し元とサブルーチン内の変数(受け取った引数)は、互いに影響を及ぼすことはありません。ただし、クラス型のオブジェクトを保持するオブジェクト変数においては、この挙動が少し変わります。
Private Sub SetName(ByVal Target As Person)
Target.Name = txtName.Text
End Sub何気なく、こんなコードを書いたことはありませんか?さて、このコードには、何か不具合があるでしょうか。
このサブルーチンの意図は、渡されたオブジェクトの Name プロパティを変更することです。しかし、よく考えてみてください。“ByVal の常識”を当てはめると、この Target は、呼び出し元で指定された変数とは異なる変数なので、これをここでどうこうしても、呼び出し元には、一切影響しないはず。これで良いのでしょうか?
やってみるとわかりますが、このコードは、意図した通りの動きをしてくれます。呼び出し元にあるオブジェクトインスタンスの Name が変更されるのです。これは、「オブジェクトインスタンスを格納している変数の場合、たとえ ByVal 渡しであっても、その中身は、元と同じものを指している」ことを示します。
もちろん、“ByVal の原則”は守られているので、
Private Sub Test(ByVal Target As Person)
Set Target = Nothing
End Subこのコードは、呼び出し元には影響しません。
Private Sub Test(ByRef Target As Person)
Set Target = Nothing
End Subこうすると、呼び出し元にも影響します。
また、Function、および Property Get プロシージャの戻り値も「値渡し」で返されます。