VB.NET継承の深淵:ShadowsとOverridesを使いこなす「設計の美学」
こんにちは。現場で「動くコード」を作るだけでなく、「10年後も壊れないコード」を追い求めるエンジニアの皆さん。
今日は、VB.NETの継承における最大の関門であり、ここを理解できるかどうかが「コードを書く人」と「システムを設計する人」の分かれ道となる、`Shadows` と `Overrides` の違いについてお話しします。
この二つ、どちらも「親クラスの機能を書き換える」ように見えますが、その魂(メモリ上の挙動とポリモーフィズム)は全くの別物です。ここを曖昧にすると、バグの温床になります。じっくりと紐解いていきましょう。
—
1. 「上書き(Overrides)」とは:ポリモーフィズムの王道
`Overrides` は、オブジェクト指向の華である「ポリモーフィズム(多態性)」を支える柱です。
親クラスで `Overridable` と宣言されたメソッドを、子クラスで `Overrides` することで、「実行時に、そのオブジェクトが何者であるかによって振る舞いが変わる」状態を作ります。
Public Class BaseClass
‘ Overridableがないと、子クラスでOverridesできません
Public Overridable Sub ShowMessage()
Console.WriteLine(“親クラスのメッセージ”)
End Sub
End Class
Public Class DerivedClass
Inherits BaseClass
‘ 実行時の型がDerivedClassであれば、必ずこちらが呼ばれます
Public Overrides Sub ShowMessage()
Console.WriteLine(“子クラスで上書きされたメッセージ”)
End Sub
End Class
なぜこれが重要か?
たとえ変数の型が `BaseClass` であっても、実体が `DerivedClass` であれば、`Overrides` されたメソッドが呼び出されます。「誰であるか」という実体に基づいた正しい振る舞い。これがオブジェクト指向の設計思想です。
—
2. 「隠蔽(Shadows)」とは:名前の衝突を力技で解決する
一方、`Shadows` はポリモーフィズムとは無縁です。「親クラスのことは知っているが、同じ名前のメソッドを(あえて)定義して、親のメソッドを見えなくする」という強引な名前の隠蔽です。
Public Class BaseClass
Public Sub Execute()
Console.WriteLine(“親クラスの処理”)
End Sub
End Class
Public Class DerivedClass
Inherits BaseClass
‘ 親のExecuteを隠蔽する
Public Shadows Sub Execute()
Console.WriteLine(“子クラスの隠蔽された処理”)
End Sub
End Class
Shadowsの決定的な違い
ここが重要です。`Shadows` の場合、「変数の型が何であるか」によって、呼ばれるメソッドが確定します。
Dim obj As BaseClass = New DerivedClass()
obj.Execute() ‘ 結果: “親クラスの処理” が出力される!
`Overrides` の時は「実体が子だから子のが呼ばれた」のに、`Shadows` だと「変数が親型だから親のが呼ばれる」のです。これが意図しないバグの最大の原因となります。
—
3. なぜ使い分けるのか?「設計の極意」
では、なぜ `Shadows` なんていう紛らわしいものがあるのでしょうか?
Overridesを使うべき場面
- 「拡張」したいとき。
- 親クラスの機能を残しつつ、中身を差し替えて「振る舞いを柔軟に変えたい」場合。これはオブジェクト指向の王道です。
Shadowsを使うべき場面
- 「切断」したいとき。
- 外部ライブラリなどの「自分では変更できないクラス」を継承した際、親クラスのメソッドが邪魔になる、あるいはシグネチャを完全に変えてしまいたい場合。
- 既存の設計を継承しつつ、明示的に「親とは別物です」と宣言したい場合。
—
4. プロフェッショナルからのアドバイス:警告を見逃さない
VB.NETのコンパイラは優秀です。もし `Shadows` を忘れて同じ名前のメソッドを書いても、警告が出ます。
> 「’Public Shadows’ を宣言しない場合、親クラスのメンバが隠蔽されます」
この警告を無視してはいけません。`Shadows` を付けるということは、「私はあえて親の機能を隠蔽し、意図的にこの挙動を選択しました」という設計上の意思表示だからです。
まとめ:今日から使えるチェックリスト
1. ポリモーフィズムを利用したいか? → はい:`Overrides` を使う。
2. 型によって挙動を固定したいか? → はい:`Shadows` を使う。
3. 迷ったら? → 継承ではなく「コンポジション(クラスを保持する設計)」を検討する。
継承は強力なツールですが、深入りしすぎると複雑性を招きます。`Overrides` は継承の目的のために、`Shadows` は名前の衝突を回避する安全装置として。この使い分けができるようになれば、あなたのコードは格段に「プロフェッショナル」なものになります。
さあ、次はどんな複雑なクラス階層に挑みますか?応援していますよ。
