|
書籍転載
文法からはじめるプログラミング言語Microsoft Visual Basic入門
VB開発者のための演算子のオーバーロード入門
―第11章 高度なプログラミング〜プログラミングの世界を広げる(前編)―
WINGSプロジェクト 高江 賢(監修 山田 祥寛)
2010/10/20 |
|
本コーナーは、日経BPソフトプレス発行の書籍『文法からはじめるプログラミング言語Microsoft Visual Basic入門』の中から、特にInsider.NET読者に有用だと考えられる章や個所をInsider.NET編集部が選び、同社の許可を得て転載したものです。基本的に元の文章をそのまま転載していますが、レイアウト上の理由などで文章の記述を変更している部分(例:「上の図」など)や、図の位置などを本サイトのデザインに合わせている部分が若干ありますので、ご了承ください。『文法からはじめるプログラミング言語Microsoft Visual Basic入門』の詳細は「目次情報ページ」もしくは日経BPソフトプレスのサイトをご覧ください。 |
ご注意:本記事は、書籍の内容を改変することなく、そのまま転載したものです。このため用字用語の統一ルールなどは@ITのそれとは一致しません。あらかじめご了承ください。 |
●11.4 演算子のオーバーロード(Visual Basic 2005)
Visual Basic 2005からは、「+」や「-」などの言語に組み込まれた演算子を、ユーザー独自の機能で拡張することができます。これを、演算子のオーバーロードと呼びます。演算子のオーバーロードを用いると、演算子が持っている機能から処理を連想することができ、わかりやすく簡潔で読みやすいコードが記述できるようになります。
演算子に追加するユーザー独自の機能は、クラスや構造体のメソッドとして定義しますが、どの演算子でもオーバーロードできるわけではありません。オーバーロードできるのは、次の表に示す演算子に限られています。
演算子 |
記号 |
単項演算子 |
+ - Not IsTrue IsFalse CType |
二項演算子 |
+ - * / \ & Like Mod And Or Xor
^ << >> = <> > < >= <= |
|
オーバーロード可能な演算子 |
○11.4.1 単項演算子と二項演算子のオーバーロード
演算子をオーバーロードするには、次のようにOperatorステートメントを用いて定義します。アクセスレベルはPublicで、共有メソッド(Shared)である必要があります。
Public Shared Operator 演算子(パラメータリスト) As 戻り値のデータ型
' 演算子として定義する処理
End Operator |
|
[構文]演算子をオーバーロードするメソッド |
単項演算子なら1つ、二項演算子なら2つのパラメータを受け取ります。戻り値とパラメータのうち少なくとも1つは、演算子を定義するクラス自身となります。また、オーバーロード演算子は、Returnステートメントを使用して結果を返す必要があります。Exitステートメントは使用できません。
それでは、実際のサンプルコードを見てみましょう。なお、演算子に割り当てる処理の内容に制限はありませんが、本来の演算子から直感的にわかるようなものにするべきです。たとえば、「+」演算子にオブジェクトを削除する処理を割り当てたとしたら、使用するときに混乱するでしょう。予想と異なる結果を返すようなオーバーロードは避けるべきです。
次のサンプルコードでは、Integer型とString型のフィールドを持つクラスで二項演算子をオーバーロードしています。「+」演算子に、2つのクラスのInteger型のフィールドの数値を加算し、String型のフィールドの文字列を連結する処理を割り当てています。
Class TestClass
Dim num As Integer
Dim str As String
Public Sub New(ByVal num As Integer, ByVal str As String)
Me.num = num
Me.str = str
End Sub
Public Sub output()
Console.WriteLine(Me.num)
Console.WriteLine(Me.str)
End Sub
' +演算子のユーザー定義
Public Shared Operator +(ByVal a As TestClass, _
ByVal b As TestClass) As TestClass
Return New TestClass(a.num + b.num, a.str & b.str)
End Operator
End Class
Class MainClass
Public Shared Sub Main()
Dim a As New TestClass(1, "演算子")
Dim b As New TestClass(2, "オーバーロード")
Dim c As TestClass = a + b
c.output()
End Sub
End Class |
|
[サンプル]overload1.vb |
TestClassクラスでオーバーロードしている「+」演算子は、2つのTestClassクラスのインスタンスをパラメータとして受け取ります。そして、numフィールドの数値を加算し、strフィールドの文字列を連結して、その結果をパラメータとしてTestClassクラスのコンストラクタを呼び出します。作成されたTestClassクラスのインスタンスは演算の結果として変数cに代入され、そのフィールドの値がoutputメソッドで出力されます。
先ほどの表には複合代入演算子が含まれていませんでしたが、複合代入演算子は元の演算子をオーバーロードすると、暗黙的にオーバーロードされます。たとえば、先ほどのサンプルコードで「+=」演算子は暗黙的にオーバーロードされるので、Mainメソッドの演算の部分を次のように書き換えても、同じ結果となります。
次に、単項演算子のIsTrue演算子とIsFalse演算子を定義してみましょう。この演算子は、Visual Basic 2005から追加された演算子ですが、これを直接コードで表記することはできません。必ずオーバーロードの定義が必要となります。Ifステートメントの条件式など、Boolean型が要求されるところで利用することができます。
IsTrue演算子とIsFalse演算子をオーバーロードする場合は、必ず両方を定義する必要があります*1。また、戻り値はBoolean型でなければなりません。
*1 比較演算子についても同様です。たとえば、「<」演算子をオーバーロードした場合は、「>」演算子もオーバーロードする必要があります。 |
Class TestClass
Private num As Integer
Private str As String
Public Sub New(ByVal num As Integer, ByVal str As String)
Me.num = num
Me.str = str
End Sub
' IsTrue演算子の定義
Public Shared Operator IsTrue(ByVal a As TestClass) As Boolean
Return (a.num <> 0) AndAlso (a.str IsNot Nothing)
End Operator
' IsFalse演算子の定義
Public Shared Operator IsFalse(ByVal a As TestClass) As Boolean
Return (a.num = 0) AndAlso (a.str Is Nothing)
End Operator
End Class
Class MainClass
' True、Falseの判定
Public Shared Sub boolTest(ByVal t As TestClass)
' IsTrue演算子で判断
If t Then
Console.WriteLine("True")
Else
Console.WriteLine("False")
End If
End Sub
Public Shared Sub Main()
Dim a As New TestClass(1, "演算子")
Dim b As New TestClass(0, Nothing)
boolTest(a) ' 出力値:True
boolTest(b) ' 出力値:False
End Sub
End Class |
|
[サンプル]overload2.vb |
TestClassのフィールドのnumが0以外かつstrがNothingでない場合はTrue、そうでない場合はFalseとなるように定義しています*2。
*2 コンパイル時はIsTrueとIsFalseの両方の演算子の定義がないとエラーになりますが、ほとんどの場合、実際のプログラムではIsTrue演算子しか評価されません。このサンプルコードでもIsTrue演算子だけが呼び出されます。 |
○11.4.2 CType演算子のオーバーロード
ユーザー定義のクラスや構造体の型変換を、独自に定義することができます。Visual Basicでは、代入演算子はオーバーロードできないので、独自に代入の機能を定義するには、その代替として型変換を定義することになります。
ユーザー定義の変換にも明示的な変換と暗黙的な変換があり、それぞれ別の変換として定義することができます。明示的な変換とは、CType演算子を用いた変換です。前述したように、明示的な変換ではデータが失われる場合があるため、コンパイラに対して強制的な変換であるということを知らせます。明示的な変換を定義するには、Operatorキーワードの他に、Narrowingキーワードを付けます。
CType演算子を使わない暗黙的な変換も定義できます。この場合はNarrowingキーワードの代わりにWideningキーワードを付けます。暗黙的な変換だけを定義した場合は、それを明示的な変換にも使うことができます。
Public Shared Narrowing Operator CType( ByVal 引数 As 変換される型 ) 変換後の型
' 明示的な変換として定義する処理
End Operator
Public Shared Widening Operator CType( ByVal 引数 As 変換される型 ) 変換後の型
' 暗黙的な変換として定義する処理
End Operator |
|
[構文]ユーザー定義による型変換の定義 |
先ほどのクラスに、ユーザー定義の変換を加えてみましょう。
Class TestClass
Private num As Integer
Private str As String
Public Sub New(ByVal num As Integer, ByVal str As String)
Me.num = num
Me.str = str
End Sub
Public Sub output()
Console.WriteLine(Me.num)
Console.WriteLine(Me.str)
End Sub
' 明示的な変換
Public Shared Narrowing Operator CType(ByVal num As Integer) _
As TestClass
Return New TestClass(num, "明示的")
End Operator
' 暗黙的な変換
Public Shared Widening Operator CType(ByVal str As String) _
As TestClass
Return New TestClass(0, str)
End Operator
End Class
Class MainClass
Public Shared Sub Main()
' 明示的な変換
Dim a As TestClass = CType(3, TestClass)
a.output()
' 暗黙的な変換
Dim b As TestClass = "暗黙的"
b.output()
End Sub
End Class |
|
[サンプル]overload3.vb |
Integer型からは明示的に、String型からは暗黙的に、TestClass型に変換しています。実行結果を見ると、それぞれに対応する変換が実行されていることがわかります。
■
次回は拡張メソッドについて解説します。