作成日 2007/11/4
最終更新日 2007/11/12
参照型の代入操作、値渡しで関数の引数に渡した場合の動作
ここでは、オブジェクト指向プログラミングの基礎である参照型について説明します。
オブジェクト指向プログラミングをする際は、今扱っている変数が参照型なのかどうかを意識し、その変数の型はどのようなものか(どのようにメモリが確保され、値が保持されているのか)を理解しておく必要があります。
参照型(オブジェクトを参照する型)がどのようなものかについて説明します。
まず、メモリの確保について説明します。
VB、VBAで、例えば図1の赤文字の部分のように参照型の変数を宣言した場合、参照型がどのような型(※1)かに関係なく4バイト(※2)のメモリが確保されます(図2)。
■VBAでのソース
Public Function main() As
Integer Dim ws As Worksheet
'...
End Function |
図1 参照型変数の宣言(赤文字の部分)(※3)
図2 参照型変数の宣言のイメージ図
オブジェクトの先頭アドレスを格納する領域(4バイト)が確保される(※3)
この4バイトは、オブジェクトがある場所(先頭アドレス)を保持する領域です。
そして、参照型に値を代入するとは、先ほど確保したメモリ(4バイト)にオブジェクトがある場所(※4)を書き込むことを言います(図3、図4)。
■VBAでのソース
Public Function main() As
Integer Dim ws As Worksheet
Set ws =
Application.ActiveSheet
End Function |
図3 参照型変数への値の代入(赤文字の部分)
図4 参照型変数への値の代入のイメージ図
オブジェクトの先頭アドレス(4バイト)(※4)が書き込まれる
これにより、参照先のオブジェクトに対していろいろ操作が出来るようになる
つぎに、参照型変数を値渡しで(VB6.0、VBAであればByValで)関数の引数に渡した場合にどのようになるか説明します。
■VBAでのソース
Public Function main() As
Integer
Dim ws As Worksheet Set ws =
Application.ActiveSheet
Call
subFunc(ws)
End Function
Private Function subFunc(ByVal ws1 As
Worksheet)
'...
End
Function
|
図5 参照型変数を値渡し(ByVal)で関数の引数に渡した場合(赤文字の部分)(※5)
図5の場合は、スタック領域上にmain関数のローカル変数wsとは別に、subFunc関数の引数であるws1の領域が確保されます。
領域ws1の中身はmain関数のローカル変数wsの中身をコピーしたものとなります。
したがって、main関数のローカル変数wsとsubFunc関数の引数であるws1が指し示すオブジェクトは同一のものとなります(図6)。
図6 参照型変数を値渡し(ByVal)で関数の引数に渡した場合のイメージ図
subFunc関数で参照先のオブジェクトに変更を加えたら、呼び出しもとのmain関数でもその変更は有効です(当然ことですが)。
subFunc関数でws1の参照先を変えた場合(例えば、ブック2のSheet1のオブジェクトを参照するようにした場合)、呼び出しもとのmain関数内のws変数が指し示すオブジェクトは変更されません。
-----
※1:
エクセルVBAなら、WorkSheet型、Application型、Collection型など、VBE(Visual
Basic
Editor)の[オブジェクト ブラウザ]に表示されるクラス、及びObject型。
javaならjava.lang.String、java.util.Date、javax.security.auth.Subjectなど、java.lang.Objectクラス、及びそのサブクラスや配列。
※2:
「4バイト」という表現はあまりよくないです。エクセルVBAのヘルプに確かに、「4バイト」と表記されていますが、参照型のデータサイズは一般にはメモリアドレスのデータサイズです。32ビットUPUなら32÷8で4バイトですが、64ビットCPUなら64÷8で8バイトです。
※3:
この例では変数「ws」は関数内に宣言されているため、オブジェクトがある場所(先頭アドレス)を保持する領域(4バイト)はスタック領域上に確保されます。
VB6.0、VBAではローカル変数wsの先頭アドレスはVarPtr関数を使用するとわかります。VB.netやJavaでは多分、変数のアドレスを取得することは出来ないと思います。
※4:
基本的にオブジェクトはヒープ領域上にあります。
オブジェクトの先頭アドレスはObjPtr関数を使用するとわかります。VB.netやJavaでは多分、オブジェクトのアドレスを取得することは出来ないと思います。
※5:
VarPtr関数を使用すればわかりますが、main関数内のws変数と、subFunc関数のws1引数のメモリ領域は別です。
ByValではなく、ByRefで変数を渡した場合は、main関数内のws変数と、subFunc関数のws1引数のメモリ領域は同じになります。
このページを作成するのに参考にしたページです。
ただし、1番以外はだるまが以下のページをちゃんと理解してこのページを作成したとは思わないように。
このページの利用によって発生した、いかなる損害について、このホームページの作成者は責任を負いません。
このページの間違いや嘘を見つけた方、このページに書いて欲しい情報がある方は
メールをお願いします。
Microsoft 、Windows 、Visual Basic および Excel は米国Microsoft
Corporationの米国およびその他の国における登録商標または商標です。
ここではExcel® をエクセル、Visual Basic® for Applications をVBAと表記する場合があります。
Mac 、Mac OS 、Mac OS X は米国Apple Computer,Inc.の登録商標または商標です。
その他、社名および商品名、システム名称などは、一般に各社の商標または登録商標です。
このホームページの作成者はこれらの会社とはいっさい関係がありません。