「ByRefは呼び出し元の変数そのものを参照する」という感覚を、ステップ実行で体験しながら掴みます。止める位置、見るべき値、起こる変化を順に確認していきます。
準備と基本コード
Sub Lesson_ByRef()
Dim a As Long, b As Long
a = 10: b = 3
Adjust a, b ' ← この行が「呼び出し」。ByRefの効果がここから始まる
Debug.Print "a=" & a, "b=" & b
End Sub
Sub Adjust(ByRef x As Long, ByVal y As Long)
x = x + y ' ← ByRef の本丸。ここで呼び出し元 a が更新される
End Sub
VB- 狙い: Adjust内の代入が呼び出し元に波及する瞬間を、F8のステップとウォッチで可視化する。
レッスン1 呼び出し元から入り、ByRefの参照を体験
- ブレークポイントを設定:
- Adjust a, b の行と、x = x + y の行に置く(左余白クリック or F9)。
- Mainを開始:
- Lesson_ByRef を実行。呼び出し行で停止。
- ステップイン(F8)で関数へ入る:
- Adjust内に移動。ローカルウィンドウで値を確認。
- 停止直後の値は「x = 10」「y = 3」になっているはず。
- 代入行をF8で実行:
- 実行直後、ローカルで x = 13 に変化。
- ステップアウト(Ctrl+Shift+F8)で戻る:
- 呼び出し元へ復帰後、イミディエイトで
? a, bを確認。 - a = 13、b = 3(bはByValなので不変)。
- 呼び出し元へ復帰後、イミディエイトで
- ポイント:
- ByRefは別名: xはaの“別名”。xの更新は即ちaの更新。
- ByValはコピー: yはbの“値のコピー”。更新してもbは変わらない。
レッスン2 「途中で書き換え」を見抜くウォッチ設定
Sub Sneaky()
Dim a As Long, b As Long
a = 5: b = 2
Adjust a, b ' ここで a が 7 になるはず
Overwrite a ' ここで a を別の値に上書き
Debug.Print "a=" & a, "b=" & b
End Sub
Sub Overwrite(ByRef z As Long)
z = 100 ' ← ByRef経由で呼び出し元の a を上書き
End Sub
VB- ウォッチ登録:
- a を「式の内容が変化したときに中断」でウォッチ。
- 実行観察:
- Adjustの実行後に a が 7 へ変化した瞬間で停止。
- Overwriteで a が 100 に変化した瞬間でも停止。
- 狙い: どの行が、いつ、呼び出し元を書き換えたかを“自動停止”で確定させる。
レッスン3 複合型(配列やオブジェクト)のByRefを実感
配列(要素更新の波及)
Sub Lesson_Array()
Dim arr() As Long
ReDim arr(0 To 2)
arr(0) = 10: arr(1) = 20: arr(2) = 30
BumpFirst arr ' ← 配列をByRefで渡す(既定はByRef)
Debug.Print arr(0), arr(1), arr(2)
End Sub
Sub BumpFirst(ByRef a() As Long)
a(0) = a(0) + 1 ' ← 呼び出し元の配列要素が直接変わる
End Sub
VB- 観察:
- BumpFirst内で停止して
a(0)が 11 に。戻るとarr(0)も 11。
- BumpFirst内で停止して
- ポイント:
- 配列は参照性が強く、ByRefで「中身の更新が呼び出し元へ直結」する。
オブジェクト(Range/Collection)の操作
Sub Lesson_Object()
Dim c As Collection
Set c = New Collection
c.Add "A": c.Add "B"
AddC c ' 要素数が呼び出し元でも増える
Debug.Print c.Count ' → 3
End Sub
Sub AddC(ByRef col As Collection)
col.Add "C" ' ← col は c の参照。中身が増える
End Sub
VB- 観察:
- AddC後に
c.Countが 3。内部操作が即呼び出し元へ反映。
- AddC後に
レッスン4 ByValとの違いを数秒で納得
Sub Contrast()
Dim a As Long, b As Long
a = 10: b = 3
Adjust_Val a, b ' ByVal で渡すと…
Debug.Print "a=" & a, "b=" & b
End Sub
Sub Adjust_Val(ByVal x As Long, ByVal y As Long)
x = x + y ' ← x は「コピー」。呼び出し元 a は変わらない
End Sub
VB- 観察:
- 関数内では x=13 になるが、戻ると a=10 のまま。
- 結論:
- 外を変えたいなら ByRef、内部だけで使うなら ByVal。
つまずき対策のチェックリスト
- 止まらない:
- ブレーク行が通っていない。 条件分岐の外や早期Exitの手前に置いていないか確認。
- ウォッチが見えない:
- コンテキスト不一致。 ウォッチの「現在のプロシージャ」を調整。
- 副作用が多すぎる:
- 変化で中断が連発。 一時的に無効化、または「式が真のとき」で条件を絞る。
まとめの指針
- 副作用を見るならByRefの代入行にブレークポイント。
- 呼び出し前後で値をイミディエイト/ローカルで確認。
- “いつ変わったか”はウォッチの「変化で中断」で自動検出。


