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 MyClass ' (Code goes here.) End Operator
Every operator method accepts two parameters, which represent the 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 + ObjB
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 Fraction ' 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
The console code shown in Example 2-4 puts the 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 FractionTest 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
When you run this application, here's the output you'll see:
f1 = 2/3 f2 = 1/4 f1 + f2 = 11/12 f1 / f2 = 8/3 f1 - f2 = 5/12 f1 * f2 = 1/6
Usually, the parameters and the return value of an operator method 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:
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.