The objective of this article is to understand the concept of C# Polymorphism, which includes the concept of method overloading, operator overloading, and method overriding. In object-oriented programming, polymorphism means many forms. It is the Greek word poly which means many, and morphism means forms. In simple words, it gives the ability to a class to have multiple definitions for a function/method with the same name (like the same method name but a different return type and a different number of parameters). It is the pillar of object-oriented programming along with Encapsulation and Inheritance.
Polymorphism is of two types:
-
Static Polymorphism
-
Dynamic Polymorphism
Static polymorphism is often referred to as compile-time or early binding polymorphism, whereas dynamic polymorphism is referred to as run-time or late binding polymorphism. Static polymorphism is achieved using method overloading and operator overloading, whereas dynamic polymorphism is achieved using method overriding. Also, in the subsequent section of this post, you will find the implementation of operator overloading and the list of operators that can and can't be overloaded.
Classification of Polymorphism
The diagram below showcases the classification of polymorphism:
1. Static Polymorphism (Method Overloading)
This type of polymorphism is also referred to as compile-time or early binding polymorphism because the decision about which method will be called is made at the compile time. Now let's see one example of method overloading where we will give two methods the same name but different signatures (number and type of parameters) to achieve static polymorphism.
Filename: Program.cs
using System;
namespace Studytonight
{
public class Interest
{
// interest for 1 year of tenure
public double TrueBank(double amount, double rate)
{
return amount + (amount * rate);
}
public double TrueBank(double amount, double rate, string holdertype)
{
return amount + (amount * rate) + 2000;
}
}
public class Program
{
public static void Main(string[] args)
{
Interest i = new Interest();
double finalamount = i.TrueBank(5000.00, 0.1);
Console.WriteLine("Normal interest for a holder " + finalamount);
finalamount = i.TrueBank(5000.00, 0.1, "prime");
Console.WriteLine("Prime interest for a holder " + finalamount);
}
}
}
Output:
Normal interest for a holder 5500
Prime interest for a holder 7500
In the code example above, we have created a class named Interest, and in that, we have given the same method name that is TrueBank to two different methods having different signatures (number of parameters) and method definitions. We have then created the object of the Interest class and provided the parameter list. If you closely observe the above parameter list, you will come to know where the difference lies. In the first one, we have given two parameters, and in the second call, three parameters are provided. At compile-time, the respective method automatically gets called with the help of the signatures of the methods. And hence, we have achieved static polymorphism.
2. Dynamic Polymorphism (Method Overriding)
This type of polymorphism is also referred to as run-time or late binding polymorphism because of the decision about which method is to be called is made at run-time. In dynamic polymorphism, we override the base class method in the derived class using inheritance, and this can be achieved using override
and virtual
keywords. Now we will see the example of method overriding where we will give the same method name and signature (same number of parameters and type but with different definitions) too in parent and child classes.
Filename: Program.cs
using System;
namespace Studytonight
{
public class Interest
{
public virtual double TrueBank(double amount, double rate)
{
return amount + (amount * rate);
}
}
// first child class
public class SimpleInterest: Interest
{
public override double TrueBank(double amount, double rate)
{
return amount + (amount * rate) + 1000;
}
}
// second child class
public class FixedInterest: Interest
{
public override double TrueBank(double amount, double rate)
{
return amount + (amount * rate) + 1500;
}
}
public class Program
{
public static void Main(string[] args)
{
Interest i = new Interest();
double finalamount = i.TrueBank(5000.00,0.1);
Console.WriteLine("Normal interest for a holder "+finalamount);
i = new SimpleInterest();
finalamount = i.TrueBank(5000.00,0.1);
Console.WriteLine("Simple interest for a holder "+finalamount);
i = new FixedInterest();
finalamount = i.TrueBank(5000.00,0.1);
Console.WriteLine("Fixed interest for a holder "+finalamount);
}
}
}
Output:
Normal interest for a holder 5500
Simple interest for a holder 6500
Fixed interest for a holder 7000
In the above example, we have created a base class named Interest, and two derived classes that is SimpleInterest and FixedInterest. In the base class, we used the virtual
keyword with the method so that it can overriden in the derived class using the override
keyword. Here, we have given the same method name that is TrueBank and the same signature (number and type parameters) but different method definitions in the derived/child classes.
The we created the object of the Interest class and provided the parameter list. If you closely observe the above parameter list, you will find the same parameters have been provided for each method call. Here the compiler only requires TrueBank()
method to compile successfully and at the run-time desired methods get called respectively, based on which class's object is calling it.
Difference between Method Overloading and Method Overriding
The table below has all the differences listed down,
Method Overloading |
Method Overriding |
Method overloading means methods with the same name but different signature (number and type of parameters) in the same scope. |
Method overriding means methods with the same name and same signature but in a different scope. |
It is performed within a class, and inheritance is not involved. |
It requires two classes, and inheritance is involved. |
The return type may be the same or different. |
The return type must be the same. |
It is an example of compile-time polymorphism. |
It is an example of run-time polymorphism. |
Static methods can be overloaded. |
Static methods can’t be overridden. |
Operator Overloading
As we know, overloading means the same function name, but different signatures, and in operator overloading, we overload the operator instead of the actual method. Thus, operators can be considered as functions for the compiler. Keeping in mind that only a predefined set of operators can be overloaded.
To overload the operator, we need to define a function by declaring with the operator
keyword, and it must include both public
and static
modifiers. The following syntax is to overload +
operator will be,
public static class name operator + (parameters)
{
// Code to be executed
}
List of operators that can and can't be overloaded:
Operators |
Description |
+, -, !, ~, ++, --, true, false |
These unary operators take one operand can be overloaded |
+, -, *, /, % |
These binary operators take two operands and can be overloaded |
==, !=, <, >, <=, >= |
The comparison operators can be overloaded
|
&&, || |
The conditional logical operators can’t be overloaded directly but these can be evaluated by using the & and | which can be overloaded
|
+=, -=, *=, /==, %== |
The compound assignment operators can’t be overloaded
|
^, =, ? :, ->, is, new, sizeof, typeof, nameof, default |
These operators can’t be overloaded |
Let's take one practical example of operator overloading.
Filename: Program.cs
using System;
namespace Studytonight
{
public class Area
{
public int value;
public static Area operator + (Area len, Area bre)
{
Area a = new Area();
a.value = len.value + bre.value;
return a;
}
}
public class Program
{
public static void Main(string[] args)
{
Area a1 = new Area();
Area a2 = new Area();
a1.value = 10;
a2.value = 20;
Area a3 = a1 + a2;
Console.WriteLine("Addition: "+a3.value);
}
}
}
Output:
Addition: 30
In the above example, we have created an Area class and overloaded the +
operator for the class which will be overloaded to perform addition on two objects of the Area class.
We hope this article helped you to understand the concept of polymorphism in C# language. Additionally, you can refer to our previous articles on Inheritance, Classes and Objects for more related to OOPs concept.
Conclusion
Finally, knowing static and dynamic polymorphism is critical for C# writers who want to create flexible and efficient apps. Dynamic polymorphism through method overriding enables the functionality of a method to be altered in a derived class, whereas static polymorphism through method overloading provides numerous variants of a method with various arguments. Developers can create code that is simple to keep and expand over time by leveraging the strengths of both kinds of polymorphism.
Frequently Asked Questions(FAQs)
1. In C#, what is static polymorphism?
Static polymorphism is accomplished through method overloading, which defines numerous methods in a class with the same name but distinct parameters.
2. In C#, what is dynamic polymorphism?
Method overriding is used to accomplish dynamic polymorphism, in which a method in a derived class has a similar name and signature as a method in the parent class.
3. What is the distinction between rigid polymorphism and dynamic polymorphism?
Dynamic polymorphism is resolved at runtime, whereas static polymorphism is resolved at build time.
4. When should I use static polymorphism versus dynamic polymorphism?
When you want to provide numerous variants of a method with distinct parameters, static polymorphism is helpful. When you want to alter the behavior of a gene, dynamic polymorphism comes in handy.
You may also like: