2.7. Use Operators with Custom Objects
Every VB programmer is familiar with
the arithmetic operators for addition (+), subtraction (-), division
(/), and multiplication (*). Ordinarily, these operators are reserved
for .NET numeric types, and have no meaning when used with other
objects. However, in VB .NET 2.0 you can build objects that support
all of these operators, as well as the operators used for logical
operations and implicit conversion). This technique
won't make sense for business objects, but it is
extremely handy if you need to model mathematical structures such as
vectors, matrixes, complex numbers, oras demonstrated in the
following examplefractions.
Note: Tired of using clumsy syntax like ObjA.Subtract(ObjB) to
perform simple operations on your custom objects? With
VB's support for operator overloading, you can
manipulate your objects as easily as ordinary numbers.
2.7.1. How do I do that?
To
overload an operator in Visual Basic 2005, you need to create a
special operator method in your class (or structure). This method
must be declared with the keywords Public
Shared Operator, followed by
the symbol for the operator (e.g., +).
Tip: To overload an operator simply means to define
what an operator does when used with a specific type of object. In
other words, when you overload the + operator for a Fraction class,
you tell .NET what to do when your code adds two Fraction objects
together.
For example, here's an operator method that adds
support for the addition (+) operator:
Public Shared Operator+(objA As MyClass, objB as MyClass) As MyClassEvery operator method accepts two parameters, which represent the
' (Code goes here.)
End Operator
values on either side of the operator. Depending on the class and the
operator, order may be important (as it is for division).Once you've defined an operator, the VB compiler
will call your code when it executes a statement that uses the
operator with your class. For example, the compiler changes code like
this:
ObjC = ObjA + ObjBinto this:
ObjC = MyClass.Operator+(ObjA, ObjB)Example 2-3 shows how you can overload the Visual
Basic arithmetic operators used to handle Fraction
objects. A Fraction consists of two portions: a
numerator and a denominator (known colloquially as
"the top part and the bottom
part"). The Fraction code
overloads the +, -,
*, and / operators, allowing
you to perform fractional calculations without converting your
numbers to decimals and losing precision.
Example 2-3. Overloading arithmetic operators in the Fraction class
Public Structure FractionThe console code shown in Example 2-4 puts the
' The two parts of a fraction.
Public Denominator As Integer
Public Numerator As Integer
Public Sub New(ByVal numerator As Integer, ByVal denominator As Integer)
Me.Numerator = numerator
Me.Denominator = denominator
End Sub
Public Shared Operator +(ByVal x As Fraction, ByVal y As Fraction) _
As Fraction
Return Normalize(x.Numerator * y.Denominator + _
y.Numerator * x.Denominator, x.Denominator * y.Denominator)
End Operator
Public Shared Operator -(ByVal x As Fraction, ByVal y As Fraction) _
As Fraction
Return Normalize(x.Numerator * y.Denominator - _
y.Numerator * x.Denominator, x.Denominator * y.Denominator)
End Operator
Public Shared Operator *(ByVal x As Fraction, ByVal y As Fraction) _
As Fraction
Return Normalize(x.Numerator * y.Numerator, _
x.Denominator * y.Denominator)
End Operator
Public Shared Operator /(ByVal x As Fraction, ByVal y As Fraction) _
As Fraction
Return Normalize(x.Numerator * y.Denominator, _
x.Denominator * y.Numerator)
End Operator
' Reduce a fraction.
Private Shared Function Normalize(ByVal numerator As Integer, _
ByVal denominator As Integer) As Fraction
If (numerator <> 0) And (denominator <> 0) Then
' Fix signs.
If denominator < 0 Then
denominator *= -1
numerator *= -1
End If
Dim divisor As Integer = GCD(numerator, denominator)
numerator \= divisor
denominator \= divisor
End If
Return New Fraction(numerator, denominator)
End Function
' Return the greatest common divisor using Euclid's algorithm.
Private Shared Function GCD(ByVal x As Integer, ByVal y As Integer) _
As Integer
Dim temp As Integer
x = Math.Abs(x)
y = Math.Abs(y)
Do While (y <> 0)
temp = x Mod y
x = y
y = temp
Loop
Return x
End Function
' Convert the fraction to decimal form.
Public Function GetDouble( ) As Double
Return CType(Me.Numerator, Double) / _
CType(Me.Denominator, Double)
End Function
' Get a string representation of the fraction.
Public Overrides Function ToString( ) As String
Return Me.Numerator.ToString & "/" & Me.Denominator.ToString
End Function
End Structure
fraction class through a quirk-and-dirty test. Thanks to operator
overloading, the number remains in fractional form, and precision is
never lost.
Example 2-4. Testing the Fraction class
Module FractionTestWhen you run this application, here's the output
Sub Main( )
Dim f1 As New Fraction(2, 3)
Dim f2 As New Fraction(1, 4)
Console.WriteLine("f1 = " & f1.ToString( ))
Console.WriteLine("f2 = " & f2.ToString( ))
Dim f3 As Fraction
f3 = f1 + f2 ' f3 is now 11/12
Console.WriteLine("f1 + f2 = " & f3.ToString( ))
f3 = f1 / f2 ' f3 is now 8/3
Console.WriteLine("f1 / f2 = " & f3.ToString( ))
f3 = f1 - f2 ' f3 is now 5/12
Console.WriteLine("f1 - f2 = " & f3.ToString( ))
f3 = f1 * f2 ' f2 is now 1/6
Console.WriteLine("f1 * f2 = " & f3.ToString( ))
End Sub
End Module
you'll see:
f1 = 2/3Usually, the parameters and the return value of an operator method
f2 = 1/4
f1 + f2 = 11/12
f1 / f2 = 8/3
f1 - f2 = 5/12
f1 * f2 = 1/6
use the same type. However, there's no reason you
can't create more than one version of an operator
method so your object can be used in expressions with different
types.
2.7.2. What about...
...using operator overloading with other types? There are a number of
classes that are natural candidates for operator overloading. Here
are some good examples:Mathematical classes that model vectors, matrixes, complex numbers,
or tensors.Money classes that round calculations to the nearest penny, and
support different currency types.Measurement classes that have irregular units, like inches and
feet.
2.7.3. Where can I learn more?
For more of the language details behind operator overloading and all
the operators that you can overload, refer to the
"Operator procedures" index entry
in the MSDN Help.