Operator Overloading
Fundamentals of Overloading an Operator
Introduction
In elementary school, we learned how to perform arithmetic operations such as adding 2 to 5 to get 7. We also learned somehow how to add letters to create a word, how to add words to create a sentence, and how to add symbols to create abbreviations. In programming, we learn how to create classes that are made of more than one value. When necessary, we may want to add the values of objects of those classes to get new objects or new values. Unfortunately, those classes are not equipped to perform arithmetic operations or comparisons on their objects. Fortunately, if you judge it necessary, you can write code that makes it possible.
We know many of the operators available in the C# language. We also reviewed some of the ways they can be used. We saw that there are rules that must be followed when using any of those operators.
Operator overloading consists of customizing the behavior of a C# operator to be able to apply it on the values of a class. This means that you must create a special behavior in your class for a particular operator you want to use.
A class whose operators you want to overload primarily starts like any class. You can add any members you judge necessary to it. Make sure you provide appropriate and realistic constructors so the class can be initialized appropriately. The other important detail you should take care of is how the value of the class will be accessed outside; that is, by clients of the class. Probably the easiest way to do this consists of overriding the ToString() method in it.
Here is an example of a class:
public class Integer { public int Number; public Integer(int n) { Number = n; } public override string ToString() { return Number.ToString(); } }
Practical Learning: Introducing Operator Overloading
namespace Mathematics { public class Arithmetic { public static long GreatestCommonDivisor(long a, long b) { long remainder; while (b != 0) { remainder = a % b; a = b; b = remainder; } return a; } } }
using Mathematics; namespace Algebra1 { public class Rational { private long num; private long den; public Rational(long a, long b) { num = a; den = b; } public long Numerator { get { return num / Arithmetic.GreatestCommonDivisor(num, den); } set { num = value; } } public long Denominator { get { return den / Arithmetic.GreatestCommonDivisor(num, den); } set { den = value; } } public override string ToString() { long numer = num / Arithmetic.GreatestCommonDivisor(num, den); long denom = den / Arithmetic.GreatestCommonDivisor(num, den); if (denom == 1) return numer.ToString(); else return string.Format("{0}/{1}", numer, denom); } } }
To overload an operator, you must create a static method using the following formula:
public static ReturnType operator What(Argument(s)) { }
Start with the access level. This is public. After the public access level, use the static keyword.
Because the method is statically implemented, you should use the name of its class as the return type. After all, the operator will act on an object of its class type. For this reason, the method should return a value that represents its class.
After the return type, you must use the operator keyword. This is followed by the operator you want to customize. There are rules you must, and suggestions you should, follow:
Because you are creating a type of method, after the operator, add the parentheses. In the parentheses, you will add one or more arguments, depending on the operator.
Since this is a method, it must have a body delimited by curly brackets.
After defining the method, you can call it either inside or outside of its class.
Overloading an Operator
Unary Operators
A unary operator is one that acts on one value. The C# language provides many unary operators but not all can be overloaded. The unary operarors available for overloading are +, -, !, ~, ++, and --.
To overload a unary operator, pass one argument to the parentheses of the method. In the body of the method, perform the desired operation. Here is an example of overloading a unary operaor:
using System; public class Integer { public int Number; public Integer(int n) { Number = n; } public static Integer operator ~(Integer value) { int number = value.Number; int nbr = ~number; Integer natural = new Integer(nbr); return natural; } public override string ToString() { return Number.ToString(); } } public class Exercise { static int Main() { Integer nat = new Integer(1405); Console.WriteLine("The bitwise negation of {0} is {1}", nat, ~nat); return 0; } }
This would produce:
The bitwise negation of 1405 is -1406 Press any key to continue . . .
In the same way, you can overload the other operators.
Practical Learning: Overloading Unary Operators
using Mathematics;
namespace Algebra1
{
public class Rational
{
private long num;
private long den;
public Rational(long a, long b)
{
num = a;
den = b;
}
public long Numerator
{
get
{
return num / Arithmetic.GreatestCommonDivisor(num, den);
}
set { num = value; }
}
public long Denominator
{
get
{
return den / Arithmetic.GreatestCommonDivisor(num, den);
}
set { den = value; }
}
public static Rational operator ++(Rational number)
{
long result = number.Numerator + number.Denominator;
return new Rational(result, number.Denominator);
}
public static Rational operator --(Rational number)
{
long result = number.Numerator - number.Denominator;
return new Rational(result, number.Denominator);
}
public override string ToString()
{
long numer = num / Arithmetic.GreatestCommonDivisor(num, den);
long denom = den / Arithmetic.GreatestCommonDivisor(num, den);
if (denom == 1)
return numer.ToString();
else
return string.Format("{0}/{1}", numer, denom);
}
}
}
using static System.Console; namespace Algebra1 { public class Algebra { public static int Main(string[] args) { long x, y; Rational fraction = null; WriteLine("This program allows you to get a rational"); Write("Enter the numerator: "); x = long.Parse(ReadLine()); Write("Enter the denominator: "); y = long.Parse(ReadLine()); WriteLine(); fraction = new Rational(x, y); WriteLine("Fraction: {0}/{1} is equivalent to {2}\n", fraction.Numerator, fraction.Denominator, fraction); fraction = new Rational(x, y); Rational increment = ++fraction; WriteLine("Increment: {0}/{1}++ = {2}", x, y, increment); fraction = new Rational(x, y); Rational decrement = --fraction; WriteLine("Decrement: {0}/{1}-- = {2}", x, y, decrement); WriteLine("==========================================="); return 0; } } }
his program allows you to get a rational Enter the numerator: 128 Enter the denominator: 45 Fraction: 128/45 is equivalent to 128/45 Increment: 128/45++ = 173/45 Decrement: 128/45-- = 83/45 =========================================== Press any key to continue . . .
Binary Arithmetic Operators
A binary operator is one that acts on two values. The values must be of the same type. C# provides a rich set of binary operators. Those used in arithmetics are: +, -, *, /, and %.
To overloaded a binary arithmetic operator, pass two arguments to the parentheses of the method. The first arguments must be of the type of class in which you are working. The second argument can be another type. Here is an example:
using System; public class Integer { public int Number; public Integer(int n) { Number = n; } public static Integer operator ~(Integer value) { int number = value.Number; int nbr = ~number; Integer natural = new Integer(nbr); return natural; } public static Integer operator +(Integer value, int add) { int number = value.Number; int nbr = number + add; Integer natural = new Integer(nbr); return natural; } public override string ToString() { return Number.ToString(); } } public class Exercise { static int Main() { Integer nat = new Integer(248); Console.WriteLine("{0} + 35 = {1}", nat, nat + 35); return 0; } }
This would produce:
248 + 35 = 283 Press any key to continue . . .
If you want to perform the operations on two similar types of values, then the second argument must be of the same type as the first, which is the class you are using.
Practical Learning: Overloading Binary Operators
using Mathematics;
namespace Algebra1
{
public class Rational
{
private long num;
private long den;
public Rational(long a, long b)
{
num = a;
den = b;
}
public long Numerator
{
get
{
return num / Arithmetic.GreatestCommonDivisor(num, den);
}
set { num = value; }
}
public long Denominator
{
get
{
return den / Arithmetic.GreatestCommonDivisor(num, den);
}
set { den = value; }
}
public static Rational operator ++(Rational number)
{
long result = number.Numerator + number.Denominator;
return new Rational(result, number.Denominator);
}
public static Rational operator --(Rational number)
{
long result = number.Numerator - number.Denominator;
return new Rational(result, number.Denominator);
}
public static Rational operator +(Rational first, Rational second)
{
long numerator = (first.Numerator * second.Denominator) + (first.Denominator * second.Numerator);
long denominator = first.Denominator * second.Denominator;
return new Rational(numerator, denominator);
}
public static Rational operator -(Rational first, Rational second)
{
long numerator = (first.Numerator * second.Denominator) - (first.Denominator * second.Numerator);
long denominator = first.Denominator * second.Denominator;
return new Rational(numerator, denominator);
}
public static Rational operator *(Rational first, Rational second)
{
long numerator = first.Numerator * second.Numerator;
long denominator = first.Denominator * second.Denominator;
return new Rational(numerator, denominator);
}
public static Rational operator /(Rational first, Rational second)
{
long numerator = first.Numerator * second.Denominator;
long denominator = first.Denominator * second.Numerator;
return new Rational(numerator, denominator);
}
public override string ToString()
{
long numer = num / Arithmetic.GreatestCommonDivisor(num, den);
long denom = den / Arithmetic.GreatestCommonDivisor(num, den);
if (denom == 1)
return numer.ToString();
else
return string.Format("{0}/{1}", numer, denom);
}
}
}
using static System.Console; namespace Algebra1 { public class Algebra { public static int Main(string[] args) { long a, b, c, d; Rational firstFraction = null; Rational secondFraction = null; Write("This program allows you to perform "); WriteLine("an arithmetic operation on two fractions"); WriteLine("First Fraction"); Write("\tEnter the numerator: "); a = long.Parse(ReadLine()); Write("\tEnter the denominator: "); b = long.Parse(ReadLine()); WriteLine("Second Fraction"); Write("\tEnter the numerator: "); c = long.Parse(ReadLine()); Write("\tEnter the denominator: "); d = long.Parse(ReadLine()); WriteLine(); firstFraction = new Rational(a, b); WriteLine("First Fraction: {0}/{1} = {2}\n", a, b, firstFraction); secondFraction = new Rational(c, d); WriteLine("Second Fraction: {0}/{1} = {2}\n", c, d, secondFraction); WriteLine(); Rational addition = firstFraction + secondFraction; WriteLine("Addition: {0}/{1} + {2}/{3} = {4}", a, b, c, d, addition); Rational subtraction = firstFraction - secondFraction; WriteLine("Addition: {0}/{1} - {2}/{3} = {4}", a, b, c, d, subtraction); Rational multiplication = firstFraction * secondFraction; WriteLine("Addition: {0}/{1} * {2}/{3} = {4}", a, b, c, d, multiplication); Rational division = firstFraction / secondFraction; WriteLine("Addition: {0}/{1} / {2}/{3} = {4}", a, b, c, d, division); WriteLine("==========================================="); return 0; } } }
This program allows you to perform an arithmetic operation on two fractions First Fraction Enter the numerator: 128 Enter the denominator: 54 Second Fraction Enter the numerator: 88 Enter the denominator: 36 First Fraction: 128/54 = 64/27 Second Fraction: 88/36 = 22/9 Addition: 128/54 + 88/36 = 130/27 Addition: 128/54 - 88/36 = -2/27 Addition: 128/54 * 88/36 = 1408/243 Addition: 128/54 / 88/36 = 32/33 =========================================== Press any key to continue . . .
Binary Bitwise Operators
Besides the traditional arithmetic operations, C# support the ability to add or shift bits in the computer memory. These operators are the bitwise conjunction operator & and its assignment operator &=, the bitwise disjunction operator | and its assignment operator |=, the bitwise exclusion operator ^ and its assignment operator ^=, the left-shift operator << and its assigment operator <<=, the right-shift operator >> and its assignment operator >>=. When necessary, overload only the primary operator (&, |, ^, <<, >>) and its equivalent assignment operator will be automatically provided by the compiler.
To overloaded a binary operator, pass two arguments to the parentheses of the method. For the two bitwise shift operators, << and >>, the first argument must be the class in which you are working and the second argument must by a constant integer (type int). Here is an example that overloads the left bitwise shifter <<:
using System; public class Integer { public int Number; public Integer(int n) { Number = n; } public static Integer operator ~(Integer value) { int number = value.Number; int nbr = ~number; Integer natural = new Integer(nbr); return natural; } public static Integer operator <<(Integer value, int shifts) { int number = value.Number; int nbr = (number << shifts ); Integer natural = new Integer(nbr); return natural; } public override string ToString() { return Number.ToString(); } } public class Exercise { static int Main() { Integer nat = new Integer(1248); Console.WriteLine("Shifting the bits of {0} to the left by {1} bits is {2}", nat, 4, nat << 4); return 0; } }
This would produce:
Shifting the bits of 1248 to the left by 4 bits is 19968 Press any key to continue . . .
For the operators that join or disjoin two series of bits:
using System; public class Integer { public int Number; public Integer(int n) { Number = n; } public static Integer operator &(Integer operand1, int constant) { int result = operand1.Number & constant; return new Integer(result); } }
using System;
public class Integer
{
public int Number;
public Integer(int n)
{
Number = n;
}
public static Integer operator ~(Integer value)
{
int number = value.Number;
int nbr = ~number;
Integer natural = new Integer(nbr);
return natural;
}
public static Integer operator +(Integer value, int add)
{
int number = value.Number;
int nbr = number + add;
Integer natural = new Integer(nbr);
return natural;
}
public static Integer operator <<(Integer value, int shifts)
{
int number = value.Number;
int nbr = (number << shifts );
Integer natural = new Integer(nbr);
return natural;
}
public static Integer operator >>(Integer value, int shifts)
{
int number = value.Number;
int nbr = (number >> shifts);
Integer natural = new Integer(nbr);
return natural;
}
public static Integer operator &(Integer operand1, int constant)
{
int result = operand1.Number & constant;
return new Integer(result);
}
public static Integer operator &(Integer operand1, Integer operand2)
{
int result = operand1.Number & operand2.Number;
return new Integer(result);
}
public override string ToString()
{
return Number.ToString();
}
}
public class Exercise
{
public static long GreatestCommonDivisor(long a, long b)
{
long remainder;
while (b != 0)
{
remainder = a % b;
a = b;
b = remainder;
}
return a;
}
static int Main()
{
int x, y;
Console.WriteLine("This program allows you to biwise join two values");
Console.Write("Enter Value 1: ");
x = int.Parse(Console.ReadLine());
Console.Write("Enter Value 2: ");
y = int.Parse(Console.ReadLine());
Integer i1 = new Integer(x);
Integer i2 = new Integer(y);
Console.WriteLine("\n{0} & 45 = {1}", i1, i1 & 45);
Console.WriteLine("\n{0} & {1} = {2}", i1, i2, i1 & i2);
return 0;
}
}
This would produce:
This program allows you to biwise join two values Enter Value 1: 286 Enter Value 2: 1524 286 & 45 = 12 286 & 1524 = 276 Press any key to continue . . .
In the same way you can overload the other operators.
Comparison Operators
As its name implies, a comparison is used to find out whether one of two values is higher than the other. The values must be of the same type. Comparison operators go in pair. That is, if you want to compare two values for equality, you must also be able to know when they are different. For this reason, if you decide to overload a comparison operator, you must also overload its opposite:
We saw that the Object class is equipped with a method named Equals. That method makes it possible to find out whether one object is equal to another. And since all classes in a C# application derive from Object, if you decide to overload a couple of comparison operators, you should also override the Equals() method.
Practical Learning: Overloading Binary Operators
using Mathematics; namespace Algebra1 { public class Rational { private long num; private long den; public Rational(long a, long b) { num = a; den = b; } public long Numerator { get { return num / Arithmetic.GreatestCommonDivisor(num, den); } set { num = value; } } public long Denominator { get { return den / Arithmetic.GreatestCommonDivisor(num, den); } set { den = value; } } public static Rational operator ++(Rational number) { long result = number.Numerator + number.Denominator; return new Rational(result, number.Denominator); } public static Rational operator --(Rational number) { long result = number.Numerator - number.Denominator; return new Rational(result, number.Denominator); } public static Rational operator +(Rational first, Rational second) { long numerator = (first.Numerator * second.Denominator) + (first.Denominator * second.Numerator); long denominator = first.Denominator * second.Denominator; return new Rational(numerator, denominator); } public static Rational operator -(Rational first, Rational second) { long numerator = (first.Numerator * second.Denominator) - (first.Denominator * second.Numerator); long denominator = first.Denominator * second.Denominator; return new Rational(numerator, denominator); } public static Rational operator *(Rational first, Rational second) { long numerator = first.Numerator * second.Numerator; long denominator = first.Denominator * second.Denominator; return new Rational(numerator, denominator); } public static Rational operator /(Rational first, Rational second) { long numerator = first.Numerator * second.Denominator; long denominator = first.Denominator * second.Numerator; return new Rational(numerator, denominator); } public static bool operator ==(Rational first, Rational second) { if ((first.Numerator == second.Numerator) && (first.Denominator == second.Denominator)) return true; else return false; } public static bool operator !=(Rational first, Rational second) { if ((first.Numerator != second.Numerator) || (first.Denominator != second.Denominator)) return true; else return false; } public override string ToString() { long numer = num / Arithmetic.GreatestCommonDivisor(num, den); long denom = den / Arithmetic.GreatestCommonDivisor(num, den); if (denom == 1) return numer.ToString(); else return string.Format("{0}/{1}", numer, denom); } public override bool Equals(object obj) { Rational rat = (Rational)obj; if ((this.num == rat.num) && (this.den == rat.den)) return true; return false; } public override int GetHashCode() { return base.GetHashCode(); } } }
using static System.Console; namespace Algebra1 { public class Algebra { public static int Main(string[] args) { long a, b, c, d; Rational firstFraction = null; Rational secondFraction = null; Write("This program allows you to perform "); WriteLine("an arithmetic operation on two fractions"); WriteLine("First Fraction"); Write("\tEnter the numerator: "); a = long.Parse(ReadLine()); Write("\tEnter the denominator: "); b = long.Parse(ReadLine()); WriteLine("Second Fraction"); Write("\tEnter the numerator: "); c = long.Parse(ReadLine()); Write("\tEnter the denominator: "); d = long.Parse(ReadLine()); WriteLine(); firstFraction = new Rational(a, b); WriteLine("First Fraction: {0}/{1} = {2}\n", a, b, firstFraction); secondFraction = new Rational(c, d); WriteLine("Second Fraction: {0}/{1} = {2}\n", c, d, secondFraction); WriteLine(); WriteLine("{0}/{1} == {2}/{3} = {4}", a, b, c, d, firstFraction == secondFraction); WriteLine("{0}/{1} != {2}/{3} = {4}", a, b, c, d, firstFraction != secondFraction); WriteLine("==========================================="); return 0; } } }
This program allows you to perform an arithmetic operation on two fractions First Fraction Enter the numerator: 36 Enter the denominator: 8 Second Fraction Enter the numerator: 54 Enter the denominator: 12 First Fraction: 36/8 = 9/2 Second Fraction: 54/12 = 9/2 36/8 == 54/12 = True 36/8 != 54/12 = False =========================================== Press any key to continue . . .
This program allows you to perform an arithmetic operation on two fractions First Fraction Enter the numerator: 36 Enter the denominator: 14 Second Fraction Enter the numerator: 45 Enter the denominator: 20 First Fraction: 36/14 = 18/7 Second Fraction: 45/20 = 9/4 36/14 == 45/20 = False 36/14 != 45/20 = True =========================================== Press any key to continue . . .
Restricted Operators
Some operators either cannot be overloaded or depend on other operators being overloaded:
Practical Learning: Ending the Lesson
|
||
Previous | Copyright © 2010-2019, FunctionX | Next |
|