Overloading Operators
Operator Overloading is used to implement polymorphism, meaning you can have multiple interchangeable classes that implement methods and properties differently
Jan 2, 2020 • 8 Minute Read
Introduction
There is a concept in C# and many other programming languages called overloading. This is a technique for implementing polymorphism, an object-oriented programming paradigm. By definition, polymorphism means you can have multiple interchangeable classes that implement methods and properties differently. This concept applies to functions as well. You can define them in different forms, which are adjusted to different situations that your application needs to handle. A common example is a method with the same name but different parameter list.
Some important things to know about overloading:
- Overloaded methods differ in the number and type of arguments passed.
- You can have only one method with the same name, order and type of arguments. Trying to have more than one will result in a compiler error.
- The compiler does not consider the return type of overloaded methods, but it forbids you to declare two methods with the same signature and different return type.
We will start with method overloads, then turn our sights towards operator overloads.
Method Overloads
Why do we need overloading in C#? We may need a class that reacts a bit differently to different numbers of arguments passed to its methods, but we don't want to have different names for the method for each situation.
There are three distinct ways to overload a method:
- The number of parameters
- The datatypes of the parameters
- The order of parameters of methods
Let's demonstrate with an example class.
using System;
namespace Overloader
{
class Mathher
{
public int Multiply(int a, int b)
{
return (a * b);
}
public string Multiply(int a, string b)
{
string result="";
for (int i = 0; i < a; i++)
{
result = result + b;
}
return result;
}
public string Multiply(string a, int b)
{
string result = "";
for (int i = 0; i < b; i++)
{
result = result + a;
}
return result;
}
static void Main(string[] args)
{
Mathher m = new Mathher();
int a = 10;
int b = 20;
Console.WriteLine($"Calling the Multiply function with two integers -> int({nameof(a)}):{a}, and int({b}):{b}");
Console.WriteLine($"Result: {m.Multiply(a, b)}");
int c = 15;
string d = "P";
Console.WriteLine($"Calling the Multiply function with one integer and one string -> int({nameof(c)}):{c}, and str({d}):{d}");
Console.WriteLine($"Result: {m.Multiply(c, d)}");
int e = 9;
string f = "K";
Console.WriteLine($"Calling the Multiply function with one string and one integer -> str({nameof(e)}):{e}, and int({f}):{f}");
Console.WriteLine($"Result: {m.Multiply(e, f)}");
Console.ReadKey(); ;
}
}
}
In this class I demonstrated the three distinct ways to overload a method of my class. The first signature returns an integer from two input integers, which is the product of their multiplication. The second signature takes an integer and a string and repeats the string integer-number of times. The third one is needed to complete the circle, meaning we can call the method with a string and an integer as arguments and it also produces the string integer-number of times.
Calling the Multiply function with two integers -> int(a):10, and int(20):20
Result: 200
Calling the Multiply function with one integer and one string -> int(c):15, and str(P):P
Result: PPPPPPPPPPPPPPP
Calling the Multiply function with one string and one integer -> str(e):9, and int(K):K
Result: KKKKKKKKK
Operator Overloads
C# provides operators that are supported by the built-in types. There are many types of operators, and probably the most common one is the arithmetic operator, which you are already familiar with. Operators have precedence that defines the order in which they are evaluated, and they have strict rules too. If you are interested in learning more about the importance of order, read my corresponding guide. The reason developers usually add operators to their custom types or classes is to provide compatibility with the operators that already work with built-in types. The other reason is that you may want to provide similar functionality to those built-in operators. This is a very detailed cover about the operators you are able to overload.
Imagine, if you will, that you would like to create a little mathematical application that produces the total surface of two triangles in 2D space.
You could construct your class with the following definition to add two triangles with instance methods.
Triangle tri1 = new Triangle(2,3,4);
Triangle tri1 = new Triangle(10,15,20);
Triangle result = tri1.Add(tri2);
You could implement the solution with static methods as well.
Triangle tri1 = new Triangle(2,3,4);
Triangle tri1 = new Triangle(10,15,20);
Triangle result = Triangle.Add(tri1,tri2);
Let's make this look more professional and try to overload our operator to harness the power of the C# capability.
Triangle tri1 = new Triangle(2,3,4);
Triangle tri1 = new Triangle(10,15,20);
Triangle result = tri1 + tri2;
Let's create our class, which supports the above. We need two constructors with different signatures, and we need to override the + operator to achieve this. There is a simple formula to help you calculate the surface of the triangle: T = (a * ma) / 2. This is the length of one side multiplied by the shortest distance between that side and the intersection of the two other sides, then divided by 2.
using System;
namespace Overloader
{
public class Triangle
{
public int a;
public int ma;
public double surface;
public Triangle(int a, int ma)
{
this.a = a;
this.ma = ma;
this.surface = (a * ma) / 2;
}
public Triangle(double surface)
{ this.surface = surface; }
public static Triangle operator +(Triangle tri1, Triangle tri2)
{
Triangle result = new Triangle((tri1.surface + tri2.surface));
return result;
}
}
class Mainer
{
static void Main(string[] args)
{
Triangle tri1 = new Triangle(8, 12);
Console.WriteLine($"The first triangle: {nameof(tri1)} with surface is:{tri1.surface}");
Triangle tri2 = new Triangle(14, 16);
Console.WriteLine($"The second triangle: {nameof(tri2)} with surface is:{tri2.surface}");
Triangle tri3 = tri1 + tri2;
Console.WriteLine($"The third triangle: {nameof(tri3)} with surface is:{tri3.surface} is the product of {nameof(tri1)} and {nameof(tri2)}");
Console.ReadKey(); ;
}
}
}
In our operator override, we simply return a new instance, which is created with the constructor that takes one and only one argument, which is the surface.
Calling the class will produce the following result.
The first triangle: tri1 with surface is:48
The second triangle: tri2 with surface is:112
The third triangle: tri3 with surface is:160 is the product of tri1 and tri2
The nameof operator is only used to print the name of the variables dynamically. It takes an object and it returns a string with its name.
Conclusion
Overloading has two distinct categories. One is for class methods, and the other is for operators. Both are very straightforward concepts which are easy to grasp and bring new functionality to your application. In this guide, we learned how to overload methods and extend our class with unique functionality, then we revisited the idea and overloaded a built-in operator that allows us to calculate the total sum of the surface of two triangles. I hope this was informative for you and you found what you were looking for. Thank you for reading.