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 LearningPractical Learning: Introducing Operator Overloading

  1. Start Microsoft Visual Studio
  2. To start a new application, on the main menu, click File -> New -> Project...
  3. In the middle list, click Class Library (.NET Framework)
  4. Change the Name to Mathematics
  5. Click OK
  6. In the Solution Explorer, right-click Class1.cs and click Rename
  7. Type Arithmetic.cs and press Enter
  8. Read the text on the message box and click Yes
  9. Change the file as follows:
    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;
            }
        }
    }
  10. To create the library, in the Solution Explorer, right-click Mathematics and click Build
  11. To create a new project, on the main menu, click File -> New -> Project...
  12. In the right list, click Console App (.NET Framework)
  13. Change the name to Algebra1
  14. Click OK
  15. In the Solution Explorer, under Algebra1, right-click References and click Add Reference...
  16. Click the Browse button
  17. Locate the folder where the Mathematics library was created
  18. Select Mathematics.dll
  19. Click OK
  20. On the main menu, click View and click Class View
  21. To create a new class, in the Class View, right-click Algebra1 -> Add -> Class...
  22. Set the Name to Rational
  23. Click Add
  24. Change the file as follows:
    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);
            }
        }
    }

The Formula

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 LearningPractical Learning: Overloading Unary Operators

  1. Change the Rational class as follows:
    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);
            }
        }
    }
  2. In the Solution Explorer, right-click Program.cs -> Rename
  3. Type Algebra to get Algebra.cs, and press Enter
  4. Read the text on the message box and click Yes
  5. Complete the file as follows:
    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;
            }
        }
    }
  6. To execute the application, on the main menu, click Debug -> Start Debugging
  7. When requested, enter the numerator as 128 and press Enter
  8. Enter the denominator as 54 and press Enter
    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 . . .
  9. Press Enter to close the window and return to your programming environment

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 LearningPractical Learning: Overloading Binary Operators

  1. Access the Rational.cs file and change it as follows:
    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);
            }
        }
    }
  2. Access the Algebra.cs file and change it as follows:
    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;
            }
        }
    }
  3. To execute the application, on the main menu, click Debug -> Start Debugging
  4. When requested, enter the first numerator as 128 and press Enter
  5. Enter the first denominator as 54 and press Enter
  6. Enter the second numerator as 88 and press Enter
  7. Enter the second denominator as 36 and press Enter
    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 . . .
  8. Press Enter to close the DOS window and return to your programming environment

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:

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 LearningPractical Learning: Overloading Binary Operators

  1. Access the Rational.cs file and change it as follows:
    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();
            }
        }
    }
  2. Access the Algebra.cs file and change it as follows:
    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;
            }
        }
    }
  3. To execute the application, on the main menu, click Debug -> Start Debugging
  4. When requested, enter the first numerator as 36 and press Enter
  5. Enter the first denominator as 8 and press Enter
  6. Enter the second numerator as 54 and press Enter
  7. Enter the second denominator as 12 and press Enter
    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 . . .
  8. Press Enter to close the DOS window and return to your programming environment
  9. To execute the application again, on the main menu, click Debug -> Start Debugging
  10. When requested, enter the first numerator as 36 and press Enter
  11. Enter the first denominator as 14 and press Enter
  12. Enter the second numerator as 45 and press Enter
  13. Enter the second denominator as 20 and press Enter
    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 . . .
  14. Press Enter to close the window and return to your programming environment

Restricted Operators

Some operators either cannot be overloaded or depend on other operators being overloaded:

Practical LearningPractical Learning: Ending the Lesson


Previous Copyright © 2010-2019, FunctionX Next