Operator Overloading

By default, out of the various C# operators, only the dot operator can be applied to user-defined types. Consider the following code snippet:-

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Program
{
    static void Main(string[] args)
    {
        Car Car1 = new Car();
        Car Car2 = new Car();
 
        Car Car3 = Car1 + Car2;
    }
}
 
class Car
{
    public int Speed;
    public string Name;
}

The compiler generates an error at line 8 saying that the operator + cannot be applied to objects of the Car class. How is the compiler supposed to know whether we want to add the speeds of two cars or concatenate their names. This is where the concept of Operator Overloading jumps in. Before we see how the + operator is prepared to work with the objects of the Car class, we need to understand how the concept works. Given below is a code snippet which accomplishes the addition in objects using a specialized method – Add().

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
using System;
 
class Program
{
    static void Main(string[] args)
    {
        Car Car1 = new Car();
        Car Car2 = new Car();
        Car1.Speed = 30;
        Car2.Speed = 70;
 
        Car Car3 = Car.Add(Car1, Car2);
        Console.WriteLine("Car3's Speed = {0}", Car3.Speed);
        Console.Read();
    }
}
 
class Car
{
    public int Speed;
    public string Name;
 
    public static Car Add(Car Car1, Car Car2)
    {
        Car NewCar = new Car();
        NewCar.Speed = Car1.Speed + Car2.Speed;
        return NewCar;
    }
}

The Add method is declared as static so it can be invoked at the class level as Car.Add(). It takes two parameters of the type Car as inputs. It then creates a new object of the Car class, with a speed equal to the sum of the speeds of the input objects – Car1 and Car2. Finally, the new object is returned. In this way, the addition of two objects can be accomplished. The same concept is used in Operator Overloading, except for the fact that the specialized function in their case are of the format operator <operator name>.

Note: The logic inside the Add function is totally up to the the programmer.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
using System;
 
class Program
{
    static void Main(string[] args)
    {
        Car Car1 = new Car();
        Car Car2 = new Car();
        Car1.Speed = 30;
        Car2.Speed = 70;
 
        Car Car3 = Car1 + Car2;
        Console.WriteLine("Car3's Speed = {0}", Car3.Speed);
        Console.Read();
    }
}
 
class Car
{
    public int Speed;
    public string Name;
 
    public static Car operator +(Car Car1, Car Car2)
    {
        Car NewCar = new Car();
        NewCar.Speed = Car1.Speed + Car2.Speed;
        return NewCar;
    }
}

As you can see, the + operator utilizes a function in the background to do its neat work. Although the concept in both the cases is same, using operators allows much greater ease. The code Car Car3 = Car1 + Car2; is much closer to the real world and its easier to type, isn’t it?

Here’s a table showing which operators can/cannot be overloaded in C#.

Operators Description
+ – ! ~ ++ — These being unary operators take one operand and can be overloaded.
+ – * / % Binary arithmetic operators take two operands and can be overloaded.
== != < > <= >= Comparison operators take two parameters and can also be overloaded.
&& || These need to be overloaded indirectly using the & and |
+= -= *= /= %= Arithmetic assignment operators cannot be overloaded.
= . ?: -> new is sizeof typeof These special operators cannot be overloaded.

Note: The overloading methods must be declared as public and static.

Overloading Prefix Unary Operators

Below is the logic to accomplish unary – operator overloading. This operator changes the sign of the relative speed and is used as: -<Object Name>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System;
 
class Program
{
    static void Main(string[] args)
    {
        Car Car1 = new Car();
        Car1.RelativeSpeed = 30;
        Car Car2 = -Car1;
    }
}
 
class Car
{
    public int RelativeSpeed;
    public string Name;
 
    public static Car operator -(Car CarObj)
    {
        Car NewCar = new Car();
        NewCar.RelativeSpeed = -CarObj.RelativeSpeed;
        return NewCar;
    }
}

Notice, that the overloaded function takes only a single parameter. If another parameter was specified, this function would overload the binary – operator. Structures being user-defined data types can also be overloaded in this fashion. The only difference is that structures being value types, can be implemented in an easier way.

1
2
3
4
5
6
7
8
9
10
11
struct Car
{
    public int RelativeSpeed;
    public string Name;
 
    public static Car operator -(Car CarObj)
    {
        CarObj.RelativeSpeed = -CarObj.RelativeSpeed;
        return CarObj;
    }
}

If the same implementation of the Operator – function was used in a class, both Car1 and Car2 would have the same RelativeSpeed of -30 after line 9. So, in the class implementation we have created a new object of the Car class.

Overloading Pre & Post Increment Operators

Unlike, C++, C# handles the Pre & Post Increment Operators by itself. Hence, we don’t need to overload them separately. Below is the implementation of the ++ operator in the Car structure.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
using System;
 
class Program
{
    static void Main(string[] args)
    {
        Car Car1 = new Car();
        Car1.RelativeSpeed = 30;
        Car Car2 = Car1++;
        Car Car3 = ++Car1;
        Console.WriteLine("Relative speed of Car1 = {0}, Car2 = {1} and Car3 = {2}"
        , Car1.RelativeSpeed, Car2.RelativeSpeed, Car3.RelativeSpeed);
        Console.Read();
    }
}
 
struct Car
{
    public int RelativeSpeed;
    public string Name;
 
    public static Car operator ++(Car CarObj)
    {
        CarObj.RelativeSpeed++;;
        return CarObj;
    }
}

At line 9, the overloaded function for the object Car1 is invoked. The operation being post increment, Car2 gets assigned the current value of Car1 which has a relative speed of 30. After this the RelativeSpeed is incremented by 1. So, Car1 has a relative speed of 31 now. In the next line, pre increment results in the value of Car1 to be incremented by 1 before the value is assigned to Car3. Car1’s RelativeSpeed is now equal to 32. This value gets copied in Car3. So, the output of the code is: Relative speed of Car1 = 32, Car2 = 30 and Car3 = 32.

If the same logic was used in the Car Class’s overloaded function, the output would be: Relative speed of Car1 = 32, Car2 = 32 and Car3 = 32. Why does this happen? As mentioned before, the class is a reference type. Hence, when we say Car1 = Car2, it implies that Car1 now points to the same object in the memory as does Car2. In structures, the same statement would be equivalent to Copy the value of Car2 in Car1.

Arithmetic Assignment Operators

Recall that, the Arithmetic Assignment operators ( += -= *= /= %= ) cannot be overloaded. This is because A += B is equivalent to A = A + B, A -= B is equivalent to A = A – B and so on. Once, you overload the binary + operator, you can perform the += operation on the objects of the class. Same is true for the rest of the Arithmetic operators.

Logical Operators

Overloading Logical Operators is a bit tricky. Firstly, to overload the && operator the function name should be operator & and for || operator it should be operator |. Secondly, before performing these boolean short-circuit operations, the true and false operators need to be defined.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
using System;
 
class Program
{
    static void Main(string[] args)
    {
        Car Car1 = new Car();
        Car Car2 = new Car();
        Car1.Running = true;
        Car2.Running = false;
 
        Car Car3 = Car1 && Car2;
        Console.WriteLine(Car3.Running);
        Console.Read();
    }
}
 
class Car
{
    public bool Running;
 
    public static Car operator &(Car Car1, Car Car2)
    {
        Car NewCar = new Car();
        NewCar.Running = Car1.Running && Car2.Running;
        return NewCar;
    }
 
    public static bool operator true(Car CarObj)
    {
        return true;
    }
 
    public static bool operator false(Car CarObj)
    {
        return false;
    }
}
No votes yet.
Please wait...