VB6.0 (Visual Basic 6.0) では、Form そのものの「型」を、実体 (インスタンス) のように扱えてしまいます。たとえば、下記コードの Form2 は、ある Form の「型」であるのにも関わらず、直接 Show メソッドを呼び出せてしまいます。
VB6.0 - フォームの「既定のインスタンス」を利用
'/** Form1 クラス */
Option Explicit
' CommandButton1 をクリックすると Form2 が表示される
Private Sub Command1_Click()
Call Form2.Show
End Sub
これは、Form2 という「型」と同名の「既定のインスタンス」があるという考え方で良いでしょう。つまり、Form2 という型にアクセスするだけで、同名のグローバルな 'Form2' が、暗黙的にインスタンス化されるということです。
暗黙的にインスタンス化された「既定のインスタンス」は、アプリケーション内全体でアクセス可能な、単一のインスタンスです。
Form2 という型で直接アクセスしようとした時に、VB が勝手にインスタンス化 (暗黙的にインスタンス化) をしています。実際、Form2 内に含まれるメンバを呼び出すと、Form2 は Initialize イベント (コンストラクタ) が実行されます。
さて、Form2 は「型」に過ぎませんから、本来は次のように「インスタンス (実体)」を生成して、そのインスタンスから Show メソッドを呼び出します。
VB6.0 - 明示的にフォームのインスタンスを生成
'/** Form1 クラス */
Option Explicit
' CommandButton1 をクリックすると Form2 が表示される
Private Sub Command1_Click()
Dim f2 As Form2
Set f2 = New Form2
Call f2.Show
End Sub
まず、インスタンスを生成して f2 に参照として Set しています。その後、f2 に含まれるインスタンスから Show メソッドを呼び出しています。
このような、正当な方法を利用するメリットはいくつかあります。
- インスタンスを生成することで、初期化が保証される
- スコープを狭めることができる (例のコードでは Command1_Click プロシージャ内でのみ有効)
- 結果、他の場所から勝手に呼び出されてしまう心配がない
- 外部のどこから操作されているのか明確になる
- 別のインスタンスを作って複製可能
既定のインスタンス (暗黙的なインスタンス化) を使用すると、上記のメリットとは逆の結果になります。
- 初期化されないので (微少の) パフォーマンス向上になる (場合もある)
- どこからでも呼び出せるので場合によっては楽 (スパゲティになることもある)
- ソースの記述量が減り、簡素化されている (ように見える)
では、既定のインスタンス (暗黙的なインスタンス化) を、防ぐにはどうすれば良いのでしょう? 既定のインスタンスが最初に使用される時は、前述したように「Initialize イベント (コンストラクタ)」が実行されます。これを、うまく利用できないかと思いついたのがこちらの方法。
VB6.0 - 既定のインスタンスの使用 (暗黙的なインスタンス化) を防ぐ
'/** Form2 クラス */
Option Explicit
' コンストラクタ
Private Sub Form_Initialize()
Set Form2 = Nothing
End Sub
上記のように、インスタンス化されたところで、とっとと参照を解放してしまうのです。この状態で、既定のインスタンスを利用しようとすると、
実行時エラー '91':
オブジェクト変数または With ブロック変数が設定されていません。
という実行時エラーが起こります。参照がないから当たり前ですよね。
グループ開発でルールを守らない方がいても、これなら安心です。仮に、Form2 のコンストラクタをコメントアウトしても、誰がコメントアウトしたのかは VSS でわかります。
さて、困ったことに、VB8 (VB2005) で、既定のインスタンス (暗黙的なインスタンス化) が復活してしまいました。VB2005 については、また明日にでも書こうと思います。
制限するためのオプションが何故ないのかと、小 1 時間(ry