overloading in C#

Constructors are also functions and can be parameterized (takes parameters as input)and they can be overloaded. They allow flexibility while creating an object. Suppose there is a Rectangle class declared in the System.Drawing namespace. It can be instantiated by either of the two methods.
 
  • Using Default Constructor
  • Using Parameterized Constructor
 
Method 1: Using default constructor
 
In this method, the bounds of the rectangle object Rect are individually set.
 
Rectangle Rect = new Rectangle();
Rect.X = 10;
Rect.Y = 20;
Rect.Width = 30;
Rect.Height = 40;
 
Method 2: Using the Parametrized Constructor
 
Rectangle Rect = new Rectangle(10, 20, 30, 40);
 
Notice that this method is more easier than previous one.. The initialization in this case is handled by the constructor of the Rectangle class.
 
The rectangle class would have an implementation similar to this one:-
 
class Rectangle
{
    public int X;
    public int Y;
    public int Width;
    public int Height;
 
    Rectangle() //Default Constructor
    {
        this.X = 0;
        this.Y = 0;
        this.Width = 0;
        this.Height = 0;
    }
 
    //Parametrized Constructor    
    Rectangle(int x, int y, int width, int height)
    {
        this.X = x;
        this.Y = y;
        this.Width = width;
        this.Height = height;
    }
}
 
Here, the class has two overloaded constructors, one being the default constructor which takes no parameter and initializes the values of X, Y, Width and Height to 0. The other one initializes these values based on the inputs to it.
 
Note: This code is just to give you an idea of how the constructors are implemented. In actual case, the rectangle class would be a lot more complex than this and would require further codes inside the constructors.
 
Function overloading
 
When you want to overload any function then we create more than one function with same name but having different parameters or different sequence or different return type. With the help of polymorphism you can create two or more function with the same name inside the same class.
 
double CircleArea(int Radius)
{
    double Area = Math.PI * Radius * Radius;
    return Area;
}
 
double CircleArea (double Radius)
{
    double Area = Math.PI * Radius * Radius;
    return Area;
}
 
The above example has two functions with the same name but having different types of input parameter.
 
int Sum (int Num1, int Num2)
{
    return Num1 + Num2;
}
 
int Sum (int Num1, int Num2, int Num3)
{
    return Num1 + Num2 + Num3;
}
 
The above example has two functions with the same name but having different numbers of parameters.
 
float Sum (int Num1, float Num2)
{
    return Num1 + Num2;
}
 
float Sum (float Num1, int Num2)
{
    return Num1 + Num2;
}
 
The above example has two functions with the same name but having different sequence of input parameters.
 
double CircleArea(int Radius)
{
    double Area = Math.PI * Radius * Radius;
    return Area;
}
 
int CircleArea(int Radius)
{
    double Area = Math.PI * Radius * Radius;
    return Area;
}
 
The above example has two functions with the same name but having different return type.
 
Out of the various C# operators, only the dot operator can be applied to user-defined types. Consider the following code pieces:-
 
class Program
{
    static void Main(string[] args)
    {
        Cycle cycle1 = new Cycle ();
        Cycle cycle2 = new Cycle (); 
        Cycle cycle3 = cycle1 + cycle2;
    }
}
 
class Cycle
{
    public int Speed;
    public string Name;
}
 
The compiler generates an error to saying that the operator + cannot be applied to objects of the Cycle class. How the compiler is understood that whether we want to add the speeds of two cars or concatenate their names? To remove this ambiguity, the concept of Operator Overloading has been found.
 
Before describing, how the + operator is prepared to work with the objects of the Cycle class, we need to understand how the concept of operator overloading works. Here, a code piece has been given below; which accomplishes the addition in objects using a specialized method – Add().
 
using System;
 
class Program
{
    static void Main(string[] args)
    {
        Cycle cycle1 = new Cycle();
        Cycle cycle2 = new Cycle();
        cycle1.Speed = 30;
        cycle2.Speed = 70; 
        Cycle cycle3 = Cycle.Add(cycle1, cycle2);
        Console.WriteLine("cycle3's Speed = {0}", cycle3.Speed);
        Console.Read();
    }
}
 
class Cycle
{
    public int Speed;
    public string Name;
 
    public static Cycle Add(Cycle cycle1, Cycle cycle2)
    {
        Cycle NewCycle = new Cycle ();
        NewCycle.Speed = cycle1.Speed + cycle2.Speed;
        return NewCycle;
    }
}
 
The Add method is declared as static so it can be invoked at the class level as Cycle.Add(). It takes two parameters of the type Cycle 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 – cycle1 and cycle2.
 
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 .
 
Note: The logic inside the Add function is totally up to the programmer.
 
using System;
 
class Program
{
    static void Main(string[] args)
    {
        Cycle cycle1= new Cycle ();
        Cycle cycle2= new Cycle ();
        cycle1.Speed = 30;
        cycle2.Speed = 70; 
        Cycle cycle3 = cycle1+ cycle2;
        Console.WriteLine("cycle3's Speed = {0}", cycle3.Speed);
        Console.Read();
    }
}
 
class Cycle
{
    public int Speed;
    public string Name;
 
    public static Cycle operator +( Cycle cycle1, Cycle cycle2)
    {
        Cycle NewCycle = new Cycle ();
        NewCycle.Speed = cycle1.Speed + cycle2.Speed;
        return NewCycle;
    }
}
 
In the above example, the + operator utilizes a function in the background to do a smart job. Although the concept in both the cases is same, using operators allows much greater ease. The code Cycle cycle3 = cycle1 + cycle2; is much closer to the real world and its easier to type.
 
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 Pre & Post Increment Operators
 
C# handles the Pre & Post Increment Operators by itself, that’s why; we don’t need to overload them separately. The given example is the implementation of the ++ operator in the Cycle structure.
 
using System;
class Program
{
    static void Main(string[] args)
    {
        Cycle cycle1 = new Cycle();
        cycle1.RelativeSpeed = 30;
        Cycle cycle2 = cycle1++;
        Cycle cycle3 = ++cycle1;
        Console.WriteLine("Relative speed of cycle1 = {0}, 
cycle2 = {1} and cycle3 = {2}", cycle1.RelativeSpeed, 
cycle2.RelativeSpeed, cycle3.RelativeSpeed);
        Console.Read();
    }
}
 
struct Cycle
{
    public int RelativeSpeed;
    public string Name;
 
    public static Cycle operator ++(Cycle CycleObj)
    {
        CycleObj.RelativeSpeed++;
        return CycleObj;
    }
}
 
The overloaded function for the object cycle1 is invoked. The operation being post increment, cycle2 gets assigned the current value of cycle1 which has a relative speed of 30. After this the RelativeSpeed is incremented by 1.
 
So, cycle1 has a relative speed of 31 now. In the next line, pre increment results in the value of cycle1 to be incremented by 1 before the value is assigned to cycle3. cycle1’s RelativeSpeed is now equal to 32. This value gets copied in cycle3. So, the output of the code is: Relative speed of cycle1 = 32, cycle2 = 30 and cycle3 = 32.
 
If the same logic was used in the Cycle Class’s overloaded function, the output would be: Relative speed of cycle1 = 32, cycle2 = 32 and cycle3 = 32. Why does this happen? As mentioned before, the class is a reference type. Hence, when we say cycle1 = cycle2, it implies that cycle1 now points to the same object in the memory as does cycle2. In structures, the same statement would be equivalent to Copy the value of cycle2 in cycle1.
 
Logical Operators
 
Overloading the Logical Operators is a little bit difficult. 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.
 
using System; 
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.IO;
namespace ConsoleApplication4
{
   
    class Program
    {
        static void Main(string[] args)
        {
            Cycle cycle1 = new Cycle();
            Cycle cycle2 = new Cycle();
            cycle1.Running = true;
            cycle2.Running = true;

            Cycle cycle3 = cycle1 & cycle2;
            Console.WriteLine(cycle3.Running);
            Console.Read();
        }
    }

    class Cycle
    {
        public bool Running;

        public static Cycle operator &(Cycle cycle1, Cycle cycle2)
        {
            Cycle NewCycle = new Cycle();
            NewCycle.Running = cycle1.Running & cycle2.Running;
            return NewCycle;
        }

    }
}

 
Arithmetic Assignment Operators
 
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.
 
Polymorphism (Inherited Methods)
 
When we are using two or more methods with same name and same signature then an ambiguity has been created. In those cases, C# supports two different ways to solve this ambiguity i.e. Method Hiding and Method Overriding. This can be done with the help of three method head keywords: new, virtual, override.
 
The main difference between hiding and overriding relates to the choice of which method to call where the declared class of a variable is different to the run-time class of the object it references. This point is explained further below.
 
Method Overriding
 
Assume that we define a Square class which inherits from a Rectangle class (a square is being a special case of a rectangle). Each of these classes also specifies a ‘getArea’ instance method, returning the area of the given instance.
 
For the Square class to ‘override’ the Rectangle class’ getArea method, the Rectangle class’ method must have first declared that it is happy to be overridden. One way in which it can do this is with the ‘virtual’ keyword. So, for instance, the Rectangle class’ getArea method might be specified like this:
 
public virtual double getArea()
{
	return length * width;
}
 
To override this method the Square class would then specify the overriding method with the ‘override’ keyword. For example:
 
public override double getArea()
{
	return length * length;
}
 
Note that for one method to override another, the overridden method must not be static, and it must be declared as either ‘virtual’, ‘abstract’ or ‘override’. Furthermore, the access modifiers for each method must be the same.
 
The major suggestion of the provision above is that if we construct a new Square instance and then call its ‘getArea’ method, the method actually called will be the Square instance’s getArea method. So, for instance, if we run the following code:
 
Square sq = new Square(5);
double area = sq.getArea();
 
then the getArea method called on the second line will be the method defined in the Square class.
 
Note: Suppose that we declare two variables in the following way:
 
Square sq = new Square(4);
Rectangle rect = sq;
 
Then, a little bit of confusion here that variable ‘rect’ refers to ‘sq’ as a Rectangle instance (possible because the Square class derives from the Rectangle class). We can now raise the question: if we run the following code
 
double area = rect.getArea();
 
then which getArea method is actually called – the Square class method or the Rectangle class method?
 
The answer in this case is that the Square class method would still be called. Because the Square class’ getArea method ‘overrides’ the corresponding method in the Rectangle class, calls to this method on a Square instance always ‘slide through’ to the overriding method.
 
Method Hiding
 
Method hiding is a technique where one method ‘hides’ another, the hidden method does not need to be declared with any special keyword. Instead, the hiding method just declares itself as ‘new’. So, where the Square class hides the Rectangle class’ getArea method, the two methods might just be written like this:
 
public double getArea() // in Rectangle
{
	return length * width;
}

public new double getArea() // in Square
{
	return length * length;
}
 
Note that a method can ‘hide’ another one without the access modifiers of these methods being the same. So, for instance, the Square’s getArea method could be declared as private, like:
 
private new double getArea()
	{
	    return length * length;
	}
 
This leads us to an essential point. A ‘new’ method only hides a super-class method with a scope defined by its access modifier. Specially, where the access point of the hiding method is ‘private’, as in the method just described, this method only hides the super-class method for the particular class in which it is defined.
 
To make it clearer, suppose that we introduced an added class, SpecialSquare, which inherits from Square. Assume that SpecialSquare does not overwrite the getArea method. In this case, because Square’s getArea method is defined as private, SpecialSquare inherits its getArea method directly from the Rectangle class (where the getArea method is public).
 
To remember the final point about method hiding is that method calls do not always ‘slide through’ in the way that they do with virtual methods. So, if we declare two variables thus:
 
Square sq = new Square(4);
Rectangle rect = sq;
 
then run the the code piece
 
double area = rect.getArea();
 
the getArea method run will be that is defined in the Rectangle class, not the Square class.