Types of polymorphism with real-life examples

Polymorphism comes under the four pillars of object-orientated programming. The word "poly" means many, and "morphism" refers to forms. Therefore, polymorphism is the phenomenon that refers to the ability of an object to have multiple forms, that is, to act differently under different conditions.

As in object-orientated programming, we consider objects as real-life entities and form classes accordingly. Similarly, let's understand polymorphism with a real-life example. Consider a person, who can have multiple characteristics at a time, the person can be a father, a son, and an employee at the same time. The same person acts differently in different scenarios, this shows polymorphism.

Now that we have a basic idea about polymorphism, let's dive deeper into the types of polymorphism.

Types of polymorphism

The beauty of polymorphism is that the code working with different classes does
not need to know which class its using since all classes are used the same way. A real-world
example of polymorphism is a button. Everyone knows how to use a button, but what a button operates depends on what it is connected to and the context in which it is used. However, the result does not affect how it is functions.

Let's have a look at the types of polymorphism in the diagram below:

Types of polymorphism
Types of polymorphism

There are generally 2 broad types of Polymorphism:

  1. Static or compile-time polymorphism

  2. Dynamic or run-time polymorphism

Note: Polymorphism can be implemented both within a single class (using compile-time polymorphism) and across multiple classes (using runtime polymorphism).

Let's understand these types of polymorphism.

Static polymorphism

Static polymorphism, also known as compile-time and ad-hoc polymorphism, is a type of polymorphism that is resolved during the compilation phase of the program. It is achieved through method overloading and operator overloading, where the appropriate method or operator is determined based on the number or types of arguments provided during the compilation.

Static polymorphism is achieved within a class when multiple functions have the same name of the functions but different signatures, that is:

  • Changing the number of parameters

  • Changing data types of the arguments

  • Changing the order of the parameters of the method

Method overloading

public class Person {
private String name;
private int age;
// Constructor with name and age
public Person(String name) {
this.name = name;
}
public void displayInfo(String occupation) {
System.out.println("Occupation: " + occupation);
}
// Method with different number of parameters
public void displayInfo(int age, String city) {
System.out.println("age: " + age);
System.out.println("City: " + city);
}
// Method with different order of parameters
public void displayInfo(String city,int age) {
System.out.println("City: " + city);
System.out.println("age: " + age);
}
public static void main(String[] args) {
Person person1 = new Person("John");
Person person2 = new Person("Anya ");
// Display additional information (occupation)
person1.displayInfo("Software Engineer");
System.out.println();
// Display additional information (address)
person2.displayInfo(25, "New York");
person2.displayInfo("New york",25);
}}

Code explanation

The Person class has three versions of the displayInfo method, each demonstrating method overloading based on the number and types of parameters.

  1. The method with one parameter

  2. The method with two parameters

  3. The method with different parameter order

During compilation, the Java compiler determines which version of the displayInfo method to call based on the number and types of arguments provided during method invocation. For example, when person1.displayInfo("Software Engineer") is called, the first version of the displayInfo method with a String parameter is invoked. When person2.displayInfo(25, "New York") and person2.displayInfo("New York",25) are called, the second and third versions of the displayInfo method with different parameter orders are invoked, respectively.

code_drawing

Let's now look at how operator overloading works.

Operator overloading

#include <iostream>
class Complex {
private:
double real;
double imag;
public:
Complex(double real = 0.0, double imag = 0.0) : real(real), imag(imag) {}
// Overload the + operator for complex number addition
Complex operator+(const Complex& other) const {
return Complex(real + other.real, imag + other.imag);
}
// Overload the - operator for complex number subtraction
Complex operator-(const Complex& other) const {
return Complex(real - other.real, imag - other.imag);
}
// Overload the * operator for complex number multiplication
Complex operator*(const Complex& other) const {
return Complex((real * other.real) - (imag * other.imag),
(real * other.imag) + (imag * other.real));
}
// Overload the << operator for custom output
friend std::ostream& operator<<(std::ostream& os, const Complex& complex) {
os << complex.real << " + " << complex.imag << "i";
return os; }};
int main() {
Complex c1(3.0, 4.0);
Complex c2(1.5, 2.5);
Complex sum = c1 + c2;
Complex difference = c1 - c2;
Complex product = c1 * c2;
std::cout << "c1: " << c1 << std::endl;
std::cout << "c2: " << c2 << std::endl;
std::cout << "Sum: " << sum << std::endl;
std::cout << "Difference: " << difference << std::endl;
std::cout << "Product: " << product << std::endl;
return 0;
}

Code explanation

In the code above, we define a Complex class to represent complex numbers. The class overloads the +, -, and * operators for complex number addition, subtraction, and multiplication, respectively. We also overload the << operator to customize the output of complex numbers when using cout. In this code, we saw the usage of these overloaded operators by performing arithmetic operations on complex numbers.

code_drawing

Dynamic polymorphism

Dynamic polymorphism, also known as runtime polymorphism, is a fundamental concept in object-oriented programming (OOP) that allows objects to exhibit different behaviors based on their actual types at runtime. Dynamic polymorphism is achieved through method overriding and virtual functions implementation.

Let's first go through method overriding.

Method overriding

// Base class
class Shape {
public void draw() {
System.out.println("Drawing a shape");
}
}
// Subclass Circle
class Circle extends Shape {
@Override
public void draw() {
System.out.println("Drawing a circle");
}
}
// Subclass Square
class Square extends Shape {
@Override
public void draw() {
System.out.println("Drawing a square");
}
}
public class main {
public static void main(String[] args) {
Shape shape1 = new Circle(); // Upcasting
Shape shape2 = new Square(); // Upcasting
Shape shape3 =new Shape();
shape1.draw(); // Output: "Drawing a circle"
shape2.draw(); // Output: "Drawing a square"
shape3.draw();
}}

Code explanation

In this example, the Shape class has a draw method that is overridden in its Circle and Square subclasses. During runtime, the Java virtual machine identifies the actual types of the objects, shape1 and shape2, and calls the appropriate draw method based on the object's type. This demonstrates dynamic polymorphism, where the method behavior is determined at runtime based on the actual type of the object, allowing different shapes to be drawn correctly.

code_drawing

Now that we have studied the different types of polymorphism, let's revise their differences in the comparison table below.

Comparison table


Static Polymorphism

Dynamic Polymorphism

Binding Time


Compile-Time


Run-time

Mechanism


Achieved through method overloading.


Achieved through method overriding.


Class Relationship

Class Relationship


Exists within a single class (overloaded methods).


Requires a superclass-subclass relationship (overridden methods).

Invocation


Early bining

Late binding

Performance


Slightly faster due to early binding.



Slightly slower due to late binding and dynamic resolution.

Conclusion

In conclusion, we explored the different types of polymorphism with real-life examples. Polymorphism allows code reusability providing flexibility to developers.

Copyright ©2024 Educative, Inc. All rights reserved