Public / Private は「どこから見えるか」を決めるラベル
Public と Private は、
「この変数(や Sub / Function)を、どこから見えるようにするか」
を決めるための“ラベル”です。
同じ変数宣言でも、Public を付けるか Private を付けるかで、
「プロジェクト全体から見えるグローバルな存在」にもなるし、
「このモジュールの中だけでひっそり使うローカルな存在」にもなります。
超ざっくり言うと、
Public = 外からも見えるように“公開”する
Private = 外からは見えないように“隠す”
というイメージで捉えると、かなり分かりやすくなります。
変数に付ける Public / Private
モジュールの先頭に書く変数宣言とスコープ
Public / Private を変数に付けるのは、基本的に「モジュールの先頭(プロシージャの外)」です。
Option Explicit
Public UserName As String
Private TotalCount As Long
Sub Sample()
' ここから下で UserName と TotalCount を使える
End Sub
VBここで重要なのは、
「Public / Private を付ける場所は“モジュールレベル”」
ということです。
Sub の中で Dim する変数には、Public や Private は付けません(付けられません)。
Public 変数のイメージと例
Public を付けた変数は、「プロジェクト全体(このブックのすべてのモジュール)から見える変数」になります。
標準モジュール Module1 に、こう書いたとします。
Option Explicit
Public UserName As String
Sub SetUserName()
UserName = "山田"
MsgBox "ユーザー名を設定しました"
End Sub
VB別の標準モジュール Module2 から、こう書けます。
Option Explicit
Sub ShowUserName()
MsgBox "現在のユーザーは " & UserName & " さんです"
End Sub
VBUserName は Module1 で宣言されていますが、Module2 からも普通に見えます。
これが Public 変数の「広いスコープ」です。
ただし、何でもかんでも Public にすると、
「どこからでも書き換えられる“野ざらしの共有変数”」だらけになり、
バグの原因になりやすくなります。
本当に「全体で共有したい情報」だけを Public にする、という意識がとても大事です。
Private 変数のイメージと例
Private を付けた変数は、「そのモジュールの中だけで使える変数」です。
他のモジュールからは見えません。
Module1 にこう書いたとします。
Option Explicit
Private TotalCount As Long
Sub AddCount()
TotalCount = TotalCount + 1
End Sub
Sub ShowCount()
MsgBox "合計回数: " & TotalCount
End Sub
VBModule1 の中の Sub からは、どちらも TotalCount を共有できます。
しかし、Module2 から
Sub Test()
MsgBox TotalCount ' コンパイルエラー:定義されていません
End Sub
VBと書くと、「そんな変数知らない」と怒られます。
ここでのポイントは、
「この変数は、このモジュールの中だけで完結させたい」
という意図を Private がはっきり表してくれることです。
Dim をモジュール先頭に書いた場合も、既定では「そのモジュール内だけ」のスコープですが、
Private を付けると、「あえて外から隠している」ことが読み手に伝わります。
Sub / Function に付ける Public / Private
Public Sub と Private Sub の違い
Public / Private は、変数だけでなく Sub や Function にも付けられます。
Option Explicit
Public Sub PublicProc()
MsgBox "どのモジュールからでも呼べる Sub です"
End Sub
Private Sub PrivateProc()
MsgBox "このモジュールの中からしか呼べない Sub です"
End Sub
VBPublicProc は、別のモジュールからも呼び出せます。
Sub CallPublic()
PublicProc ' OK
End Sub
VB一方、PrivateProc は同じモジュールの中からしか呼べません。
別モジュールから呼ぼうとすると、「定義されていません」というコンパイルエラーになります。
ここでもキーワードは「公開するか、隠すか」です。
外から呼んでほしい“窓口”の Sub は Public、
内部でだけ使う“裏方”の Sub は Private、
という分け方を意識すると、構造がとても分かりやすくなります。
Function に対する Public / Private
Function も同じです。
Option Explicit
Public Function Add(a As Long, b As Long) As Long
Add = a + b
End Function
Private Function InternalCalc(x As Long) As Long
InternalCalc = x * 2
End Function
VBAdd は Public なので、他のモジュールからも呼べますし、条件を満たせばワークシート関数としてセルからも呼べます。
InternalCalc は Private なので、このモジュールの中のコードからしか呼べません。
「Add の内部でだけ使う補助計算」といった位置づけにできます。
Public Function は「外に見せる API(入口)」、
Private Function は「中でだけ使う部品」
というイメージを持つと、設計の整理がしやすくなります。
Public / Private を体感する小さな例題
例題1:Public 変数で「状態を共有する」
Module1:
Option Explicit
Public LoginUser As String
Sub Login()
LoginUser = "佐藤"
MsgBox "ログインユーザーを " & LoginUser & " に設定しました"
End Sub
VBModule2:
Option Explicit
Sub ShowLoginUser()
If LoginUser = "" Then
MsgBox "まだログインしていません"
Else
MsgBox "現在のユーザーは " & LoginUser & " さんです"
End If
End Sub
VBこの場合、Login を先に実行してから ShowLoginUser を実行すると、
Module をまたいで LoginUser の値が共有されているのが分かります。
「アプリ全体で共有したい“状態”」を Public 変数に持たせると、こういうことができます。
ただし、どこからでも書き換えられるので、使いすぎは危険、という感覚も同時に持っておくと良いです。
例題2:Private Sub で“裏方処理”を隠す
Module1:
Option Explicit
Public Sub RunMain()
Initialize
Process
Finish
End Sub
Private Sub Initialize()
MsgBox "初期化中..."
End Sub
Private Sub Process()
MsgBox "処理中..."
End Sub
Private Sub Finish()
MsgBox "終了処理中..."
End Sub
VBここでは、RunMain だけを Public にして、Initialize / Process / Finish は Private にしています。
外のモジュールからは RunMain しか呼べません。
内部の細かい手順(Initialize など)は隠されていて、外からは意識しなくていい設計になっています。
「外に見せたいのはどこか」「中だけで完結させたいのはどこか」
これを意識して Public / Private を付けると、コードが“モジュール化”されていきます。
超初心者向けの実践ルール
最後に、「今の段階でこれだけ意識しておけば十分」というルールをまとめます。
変数について
まずは基本、「変数は Sub / Function の中で Dim して、その中だけで使う」。
どうしてもモジュール内で共有したいときだけ、モジュール先頭に Private で宣言する。
Public 変数は、「本当に全体で共有したい情報」に限る(乱用しない)。
プロシージャについて
外から呼んでほしい“入口”の Sub / Function だけ Public にする。
内部でしか使わない補助的な Sub / Function は Private にする。
Public / Private は、難しい文法というより、
「どこまで見せるか」「どこで閉じるか」を決める“設計の道具”です。
