What is polymorphism?
Polymorphism is a Greek word which means many forms. Poly means many and morphism means forms, it means that one object performs multiple functionalities at different points of time.
Polymorphism occurs when we have many classes and these are related to each other’s using inheritance.
We can implement polymorphism by using three different approaches:
• Overloading
• Overriding
• Hiding
There are two main types of polymorphism:
-
Compile-time (Static) Polymorphism:
This type of polymorphism is achieved through method overloading and operator overloading. Method overloading allows a class to have multiple methods with the same name but different parameter lists. The appropriate method to call is determined at compile-time based on the number and types of arguments passed. Operator overloading allows operators (like +, -, *, etc.) to be redefined for custom classes, enabling more intuitive interactions with objects of those classes.
-
Run-time (Dynamic) Polymorphism:
This type of polymorphism is achieved through method overriding. It involves the inheritance and overriding of methods from a base (or superclass) to a derived (or subclass) class. When a method is overridden in the subclass, the version of the method defined in the subclass is executed, even if the method is called through a reference to the superclass. This enables the use of a common interface while allowing different classes to provide their own implementations of the methods.
Polymorphism is a key principle of OOP and encourages code reusability and extensibility. It allows you to create more generic code that can work with a variety of different objects, promoting a more modular and maintainable software design.
Let's consider a classic example of polymorphism using a basic shape hierarchy in C#. We'll define a base class Shape and two derived classes Circle and Rectangle. Both derived classes will override a method from the base class, showcasing polymorphism in action.
using System;
class Shape
{
public virtual void Draw()
{
Console.WriteLine("Drawing a generic shape");
}
}
class Circle : Shape
{
public override void Draw()
{
Console.WriteLine("Drawing a circle");
}
}
class Rectangle : Shape
{
public override void Draw()
{
Console.WriteLine("Drawing a rectangle");
}
}
class Program
{
static void Main(string[] args)
{
Shape[] shapes = new Shape[3];
shapes[0] = new Shape();
shapes[1] = new Circle();
shapes[2] = new Rectangle();
foreach (Shape shape in shapes)
{
shape.Draw(); // Polymorphism in action
}
}
}
In this example:
-
The 'Shape' class is the base class with a virtual 'Draw()' method.
- The 'Circle' and 'Rectangle' classes are derived from 'Shape' and they both override the 'Draw()' method.
- In the 'Main' method, an array of 'Shape' objects is created and initialized with instances of 'Shape', 'Circle', and 'Rectangle'.
- When the 'Draw()' method is called within the loop, the appropriate overridden version of the method is executed based on the actual object type, demonstrating run-time polymorphism.
When you run the program, you'll see the following output:
Drawing a generic shape
Drawing a circle
Drawing a rectangle
Despite using the common base class reference type, the 'Draw()' method call behaves differently depending on the actual instance's type. This showcases the core principle of polymorphism, where different classes provide their own implementations of a common method, allowing for dynamic behavior based on the object's actual type at runtime.