Card image cap

Understanding Method Overloading and Overriding

C# Fundamentals  • Posted 4 months ago

In a previous article we have seen that in the context of Polymorphic behaviors, a compile-time polymorphism involves method overloading while a runtime polymorphism employs method overriding. In this article, let's talk in particular about what are method overloading and overriding. And we shall look at potential differences between these two characteristics.

Method overloading and overriding are two distinct characteristics of any Object oriented programming which involves a same method name with variation in either how they're composed or how they're invoked. Together, both help in extensibility and varied implementations of components.

Method Overloading:

Overloading is a phenomenon, where a method or a constructor can have different variants or flavors for itself, by means of variations in its method "signature".

A signature implies the below features of a method:

  1. The number of parameters
  2. The data types of the parameter

A method Signature doesn't comprise of its return type and it shall NOT be considered for method overloading

In short, overloading refers to "one thing many forms".

Now we can have an overloading method, or an overloading constructor since these two are the only things in a class which can take a parameter.

For example, consider the below Beast class with a single method Sound() and a number of variations of its "signature":


namespace WorkConsoleApp
{
    public class Beast
    {
        // actual method
        public void Sound()
        {
            Console.WriteLine("Beast makes a sound - grrrr");
        }

        // variation in number of parameters
        public void Sound(string sound)
        {
            Console.WriteLine($"Beast makes a sound of passed string {sound}");
        }

        // variation in the type of parameter
        public void Sound(object sound)
        {
            Console.WriteLine($"Beast makes a sound of passed object {sound}");
        }

        // variation in type and number of parameters 
        public void Sound(string sound, string name) 
        {
            Console.WriteLine($"Beast makes a string sound {sound} and its name is {name}");
        }

        // variation in type and number of parameters
        public void Sound(object sound, string name) 
        {
            Console.WriteLine($"Beast makes an object sound {sound} and its name is {name}");
        }
    }
}

Now when we run this example, we can observe that the resultant method call depends on what kind of argument we pass and how many arguments we pass:


namespace WorkConsoleApp
{
    public class NewProgram
    {
        public static void Main(string[] args)
        {
            Beast b = new Beast();
            
            // call the default
            // Sound() method
            b.Sound();

            // call Sound()
            // with a string param
            b.Sound("PowPow");

            // call Sound()
            // with an int param
            b.Sound(12345);

            // call Sound()
            // with two string arguments
            b.Sound("PowPow", "Cheetah");

            // call Sound()
            // with a string and a number
            b.Sound(12345, "Cheetah");
        }
    }
}

Will result in the below output:


Beast makes a sound - grrrr // default method
Beast makes a sound of passed string PowPow // with a string argument - overload 1
Beast makes a sound of passed object 12345 // with an integer argument - overload 2
Beast makes a string sound PowPow and its name is Cheetah // with two string arguments - overload 3
Beast makes an object sound 12345 and its name is Cheetah // with a string and a number argument - overload 4

The decision of which method overload needs to be called for the given set of arguments is taken at compile-time.

Read: Decision of Invocation - Compile-time Polymorphism and Runtime Polymorphism

How overload can be helpful?

When an implementation needs to supply more than one variant of a functionality for the same given name, without willing to have different method names for each variation in the functionality, we can simply opt for method overloading where we can define multiple implementations of a same method name, and the calling client need not worry about the method it needs to be called for the required functionality.


namespace WorkConsoleApp
{
    public class Figure
    {
        // area of a square
        public double Area(double side)
        {
            return side * side;
        }

        // area of a rectangle
        public double Area(double length, double breadth)
        {
            return length * breadth;
        }

        // area of a circle
        public double Area(double radius, bool isCircle)
        {
            if (isCircle)
                return 3.14 * Area(radius);
            else
                return Area(radius);
        }
    }
}

Method Overriding:

Overriding is a phenomenon involving two or more methods of the same name but in different classes which are related to each other as base and derived types. These methods share the same name and same signature but with different implementations depending on their types. And the base type method is "overrided" by the same method composition of its derived type when being called at the client.

For example, let's assume an Animal class which has single method Sound() that takes a single argument sound of type string. Now this Animal is a base type two three different classes Cat, Dog and Lion which too are composed of method Sound() which too takes a single argument sound of type string. This setup is shown as below:


namespace WorkConsoleApp
{
    public class Animal
    {
        public virtual void Sound(string sound)
        {
            Console.WriteLine($"Animal makes Sound - {sound}");
        }
    }

    public class Cat : Animal
    {
        public override void Sound(string sound)
        {
            Console.WriteLine($"Cat makes Sound - {sound}");
        }
    }

    public class Dog : Animal
    {
        public override void Sound(string sound)
        {
            Console.WriteLine($"Dog makes Sound - {sound}");
        }
    }

    public class Lion : Animal
    {
        public override void Sound(string sound)
        {
            Console.WriteLine($"Lion makes Sound - {sound}");
        }
    }
}

When you look at it, each of the type (Dog, Cat and Lion) can exist individually and can be referred individually for their method Sound(). But at the caller's end, the caller would never know what is the underlying implementation he's invoking. Thus he'd just call the method Sound() over a reference variable animal which is of basetype Animal, and would have its value be assigned via some functionality (say a factory, or a constructor injection).

namespace WorkConsoleApp { public class AnimalCaller { private Animal animal;

    public AnimalCaller()
    {
        // assign to Dog instance
        this.animal = new Dog();
    }

    public void CallAnimal()
    {
        animal.Sound("Cat");
    }
}

}

The decision of what method needs to be called for a variable of a specific base type is taken depending on what derived type instance is passed into it and is taken during runtime.

How overriding can be useful?

Overriding is one of the more important concept of code by abstractions and can greatly help in code extensibility. When at a later point of time, the caller needs to add an additional implementation of the base Animal type in the form of an animal Crocodile, which shall also have a Sound() method, we can simply make this Crocodile class a derivative of the base Animal type and then override the actual Sound() functionality which the animal provides with our own flavor and then substitute this new implementation for the abstract type argument the caller expects. This can greatly help with developing extensive components and is also one of the SOLID principles the Open/Closed principle. Method Overriding makes all this possible because of this characteristic.

We use cookies to provide you with a great user experience, analyze traffic and serve targeted promotions.   Learn More   Accept