Me, MyClass, MyBase 〜 MeとMyClassの違い
注意:
この文書は以前「.NETでいきまっしょい!」で公開していたものですが、公開以降メンテナンスされていません。 今や古い情報となった内容が記載されている場合があるのでご注意ください。
1.Me, MyClass, MyBase
C++、VBや、VB.NET、C#にはクラスのインスタンスが自分自身とそのメンバを参照するためのキーワードがあります。 例えばC++ではthisポインタ、VBではMeキーワードなどです。 同様にC#ではthis及びbaseキーワード、VB.NETではVBから引き続きMeが使われ、新たにMyClassとMyBaseというキーワードが採用されました。 VB.NETとC#でMyBase / baseというキーワードが採用された背景には、共通言語仕様ではクラスの多重継承が認められていないために基底クラスは常に一つであるため、C++のように任意の基底クラスを参照するためにキャストを行う必要がなくなったからと考えられます。
このようにVB.NETとC#の MyClass / this と MyBase / base はその機能や目的は同じであるといえます。 ですが、VB.NETにはMyClassに似た働きを持つMeキーワードが存在します。 MeとMyClassの機能の違いに言及する前に、Me・MyClass・MyBaseを使用した例によってその動作を見てみることにします。
Me, MyClass, MyBase
001 002 003 004 005 006 007 008 009 010
011 012 013 014 015 016 017 018 019 020
021 022 023 024 025 026 027 028 029 030
031 032 033 034 035 036 037 038 039 040
041 042 043 044 045 046 047 048 049 050
051 052 053 054 055
|
Imports System
' 基底クラス
Public Class BaseClass
' 基底クラスでのMethod()
Protected Overridable Sub Method(ByVal keyword As String)
Console.WriteLine("Method of BaseClass called by " + keyword)
End Sub
End Class
' 派生クラス
Public Class DerivedClass
Inherits BaseClass
' 派生クラスでのMethod()
Protected Overrides Sub Method(ByVal keyword As String)
Console.WriteLine("Method of DerivedClass called by " + keyword)
End Sub
' 各キーワードでインスタンスのメソッドを呼び出すためのメソッド
Public Sub CallMethods()
' MyBase による呼び出し
MyBase.Method("MyBase")
' MyClass による呼び出し
MyClass.Method("MyClass")
' Me による呼び出し
Me.Method("Me")
End Sub
End Class
' アプリケーションのエントリーポイント
Module MeMyclassMybase
Sub Main()
' 派生クラスのインスタンスを作成
Dim inst As New DerivedClass()
inst.CallMethods()
End Sub
End Module
|
| 出力結果 |
Method of BaseClass called by MyBase
Method of DerivedClass called by MyClass
Method of DerivedClass called by Me
Press any key to continue
|
この結果から分かるとおり、MyBaseはそのインスタンスの基底クラスのメンバを参照しているのに対し、MyClass及びMeはそのインスタンス自身のクラスのメンバを参照していることがわかります。 では、MyClassとMeは同じものといえるのでしょうか。 下位互換性のためにMeが残されたのでしょうか。 それともキーワードが二つあるからには何らかの違いがあるのでしょうか。
2.MeとMyClassの違い
実際のところ、全く意味の同じキーワードが二種類存在するのは下位互換性のためだけではなく、ちゃんとした違いがあります。 ほとんどの機能はMeもMyClassも大差ないのですが、メソッドの呼び出しの時にはその違いがあらわれます。 その違いがあらわれるようなサンプルコードを次に示します。
MeとMyClassの違い
001 002 003 004 005 006 007 008 009 010
011 012 013 014 015 016 017 018 019 020
021 022 023 024 025 026 027 028 029 030
031 032 033 034 035 036 037 038 039 040
041 042 043 044 045 046 047 048 049 050
051
|
Imports System
' 基底クラス
Public Class BaseClass
' 基底クラスでのMethod()
Protected Overridable Sub Method(ByVal keyword As String)
Console.WriteLine("Method of BaseClass called by " + keyword)
End Sub
' 各キーワードでインスタンスのメソッドを呼び出すためのメソッド
Public Sub CallMethods()
' MyClass による呼び出し
MyClass.Method("MyClass")
' Me による呼び出し
Me.Method("Me")
End Sub
End Class
' 派生クラス
Public Class DerivedClass
Inherits BaseClass
' 派生クラスでのMethod()
Protected Overrides Sub Method(ByVal keyword As String)
Console.WriteLine("Method of DerivedClass called by " + keyword)
End Sub
End Class
' アプリケーションのエントリーポイント
Module MeMyclassMybase
Sub Main()
' 派生クラスのインスタンスを作成
Dim inst As New DerivedClass()
inst.CallMethods()
End Sub
End Module
|
| 出力結果 |
Method of BaseClass called by MyClass
Method of DerivedClass called by Me
Press any key to continue
|
今回は先ほどとは異なり、CallMethods()を基底クラスに配置しました。 そして、派生クラスDerivedClassのインスタンスを作成し、そのインスタンスからCallMethods()を呼び出しています。 結果を見てわかるとおり、MeとMyClassでは異なる文字列を出力していることがわかります。 つまり、Me.Method()はDerivedClass.Method()を呼び、MyClass.Method()はBaseClass.Method()を呼び出しています。
これは何を意味しているかというと、MyClassはインスタンスのクラスがどのクラスであるかに関わらず、確実にMyClassが用いられたクラスのメソッドを呼び出しているのに対し、Meの場合はMeが用いられたクラスが何であるかに関わらず、インスタンスのクラスのメソッド、つまり派生クラスでオーバーライドされたメソッドを呼び出していることになります。
さらに、派生クラスで基底クラスのメソッドをシャドウするとその挙動は変化します。 次のコードはそれを行ったものです(DerivedClass.Method()のOverridesキーワードをShadowsキーワードに変えています)。
MeとMyClassの違い その2
001 002 003 004 005 006 007 008 009 010
011 012 013 014 015 016 017 018 019 020
021 022 023 024 025 026 027 028 029 030
031 032 033 034 035 036 037 038 039 040
041 042 043 044 045 046 047 048 049 050
051
|
Imports System
' 基底クラス
Public Class BaseClass
' 基底クラスでのMethod()
Protected Overridable Sub Method(ByVal keyword As String)
Console.WriteLine("Method of BaseClass called by " + keyword)
End Sub
' 各キーワードでインスタンスのメソッドを呼び出すためのメソッド
Public Sub CallMethods()
' MyClass による呼び出し
MyClass.Method("MyClass")
' Me による呼び出し
Me.Method("Me")
End Sub
End Class
' 派生クラス
Public Class DerivedClass
Inherits BaseClass
' 派生クラスでのMethod()
Protected Shadows Sub Method(ByVal keyword As String)
Console.WriteLine("Method of DerivedClass called by " + keyword)
End Sub
End Class
' アプリケーションのエントリーポイント
Module MeMyclassMybase
Sub Main()
' 派生クラスのインスタンスを作成
Dim inst As New DerivedClass()
inst.CallMethods()
End Sub
End Module
|
| 出力結果 |
Method of BaseClass called by MyClass
Method of BaseClass called by Me
Press any key to continue
|
今度はMeもMyClassもBaseClass.Method()を呼び出しています。 このように、メソッドの呼び出しではMeとMyClassは多少挙動が異なるので注意が必要です。 通常の使用方法ならMyClassを用いた方がよけいなバグを生じる可能性は少ないと思います(しかし、VB時代からの習慣で、ついMeを使いたくなってしまうのがホントのところです・・・)。