What is Polymorphism in OOPs

In Object Oriented Programming, there is a significant concept that can help us to reuse the code in various contexts without the need to rewrite the same code many times. It helps in the code duplication and enhances maintainability of the code. In this blog let us understand about what is Polymorphism? Why do we use Polymorphism and what are the ways through which Polymorphism can be achieved with examples. So without any ado, let's go through the blog.

What is Polymorphism?

The word polymorphism is the combination of poly that indicates “many” and morph indicates “forms” which collectively indicates “An object that has many forms”.  An Object oriented programming language includes classes and objects using a single interface which would use the concepts of function overloading, function overriding and virtual functions. 

Polymorphism refers to the ability to take many forms. It is an important concept in object oriented programming which enables the interface/method to be used with different classes or data types. It enables you to create objects, variables and methods that can have  multiple forms. In Polymorphism, the class objects inherited from a common parent class will have the functions with the same name but behave differently.

One of the real time examples is a woman. She acts as a wife to her husband, acts as a mother to her children, acts as an employee to the employer at the same time but in different situations. Here the woman is exhibiting different behaviour in different situations. This is called Polymorphism. 

Why is Polymorphism used?

Polymorphism is one of the important concepts in OOPs concepts. It allows us to write adaptable and flexible code that can work with a variety of objects without knowing their specific type at compile time. Following are some of the reasons why Polymorphism is important in object Oriented Programming.

  • Reusability: We can write the code that can be reused in different scenarios without the need to rewrite the same code for different classes or data types. It reduces the code duplication and enhances the code maintainability.
  • Flexibility: It allows us to write code that is very flexible and is adaptable to changes. It enables us to add new classes that will inherit from a common superclass and utilise polymorphism to work with these new classes without making any changes to the existing code.
  • Code Organization: It enables us to organise the code into logical and manageable structure. For a group of related classes, you can define a common interface grouping them together and work with them in a consistent way.
  • Abstraction: It allows us to work with objects at a higher level of abstraction. Rather than specific implementation details, you could focus on the common properties and behaviours of a group of objects.

Java Certification Training

  • Master Your Craft
  • Lifetime LMS & Faculty Access
  • 24/7 online expert support
  • Real-world & Project Based Learning

Let us Understand  Polymorphism in OOPs with a simple Example

Consider a class hierarchy that has a superclass called fruit, with three subclasses Apple, Orange and grapes. All these three subclasses inherit from fruit. The fruit class had a method known as colour(), that is overridden in the classes Apple, Orange and grapes

IMAGE

Syntax:

Syntax for the above example:


class Fruit

{

  public: Fruit(){}

  //defining a virtual function called Colour for Fruit class 

  virtual void Colour(){cout<<"Colour of the Fruit"<<endl;} 

};

class Apple: public Fruit

{

  public: Apple(){}

  //Colour function defined for Apple class

  virtual void Colour(){cout<<"Red"<<endl;} 

};


class Orange: public Fruit

{

  public: Orange(){}

  //Colour function defined for Orange class

  virtual void Colour(){cout<<"Orange"<<endl;}

};


class Grapes: public Fruit

{

  public: Grapes(){}

  //Colour function defined for Grapes class

  virtual void Colour(){cout<<"Green"<<endl;}

};


int main() {


  Fruit *f; 

  Orange O;

  Apple A;

  Grapes G;

  // store the address of Apple

  f = &A;

  // call Apple Colour function

 f->Colour();

  // store the address of Orange

  f = &O;

  // call Orange Colour function

  f->Colour();

  // store the address of Grapes

  f = &G;

  // call Grapes Colour function 

  f->Colour();

  return 0;

}

In the above example, We have used polymorphism to call the same method “Colour()” on different objects and the method resulted in the different output depending on the type of object. This is how Polymorphism works. It enables you to write the code that can work with distinct objects without the need to know their specific type at the compile time.

Polymorphism is achieved in Different Ways:

  1. Compile Time Polymorphism
  2. Runtime Polymorphism.

IMAGE

Compile Time Polymorphism

Compile time polymorphism is also called static binding or early binding. It is a type of Polymorphism that is achieved either by method/function overloading  or Operator overloading. The overloaded functions will be invoked by matching the number of arguments and type of arguments. The information is given during the compile time. So at the compile time, appropriate functions will be selected. 

Compile time polymorphism is achieved by method/function overloading and operator overloading.

Method Overloading

It enables us to define several methods in the same class using the same name providing different parameter lists. When a method is called, then the compiler will determine which method to be invoked depending on the number, type and order of arguments passed. It will allow us to use the same method name for different operations on different data types.

Example:

#include 

using namespace std;

class addition

{

public:

int addition(int a, int b)

{

return a + b;

}

float addition(float a, float b, float c)

{

return a + b + c;

}

};

int main(void)

{

addition add;

cout << add.addition(4, 5) << endl;

cout << add.addition(1.2, 4.3, 7.1) << endl;

return 0;

}

Output:

9

12.6

In the above example, the addition class has two addition methods with the same name but different parameter types (integers and float). When a method is called, then the compiler will determine which method to be invoked depending on the number, type and order of arguments passed.

Operator overloading

It allows operators like  -, +, *, etc., to be overloaded and used with various types of operands. The overloaded operators' behaviour is according to the types of Operands involved. 

Example

#include     

using namespace std;    

class Demo    

{    

   private:    

      int num;    

   public:    

       Demo(): num(6){}    

       void operator ++()         {     

          num = num+3;     

       }    

       void Print() {     

           cout<<"the result is : "<<num;     

       }    

};    

int main()    

{    

    Demo d;    

    ++d;  // calling of a function "void operator ++()"    

    d.Print();    

    return 0;    

}    


Output:

the result is : 9

2) Runtime Polymorphism

Runtime Polymorphism is also called dynamic binding or late binding. It  is achieved by method overriding when the method of the object is invoked at the run time rather than during the compile time. Runtime polymorphism can be achieved by method overriding and virtual functions.

Subscribe to our YouTube channel to get new updates..!

Method Overriding

 It enables subclasses to offer a different implementation of the method which is defined already in the superclass.When the method is called on an object of the subclass, the method that is overridden in the subclass will be executed rather than the method in the superclass. It  allows us to offer a specific implementation of the method in the subclass which is different from the implementation in the superclass. 

Example

#include   

using namespace std;  

class Animal {  

public:  void sound()

{    

cout<<"making sound...";    

    }      

};   

class Cat: public Animal    

{    

 public:  

 void sound()    

    {    

       cout<<"Meow Meow...";    

    }    

};  

int main(void) {  

  Cat c = Cat();    

   c.sound();  

   return 0;  

}  




Output:

Meow Meow...
Virtual Functions

These are the functions that are declared in the base class using the Keyword “virtual” and are intended to be overridden in the derived classes. The actual functions that must be executed are dynamically determined as per the object type.

Example

#include   

using namespace std;  

class Draw {

public:

    virtual void start() {

        cout << "Start to Draw" << endl;

    }

};


   class Circle : public Draw {

   public:

       void start() {

           cout << "Draw a circle" << endl;

       }

   };


   int main() {

     Draw* dPtr;

       Circle cObj;


      dPtr = &cObj; // Assigning address of Circle object to the base class pointer


      dPtr->start(); // Output: Draw a circle


       return 0;

   }

In the above example, we have written a base class Shape with a virtual function draw(). Here the Circle class inherits from the Shape class and overrides the draw() function with its own implementation. In the main() function, we have declared a pointer dPtr of type Shape* and created a Circle object cObj. Then  we have assigned the address of the cObj to the dPtr. This is because of the "is-a" relationship between Circle and Shape.

When we call the draw() function through the pointer dPtr, the overridden version of the draw() function in the Circle class is executed at runtime. This is called runtime polymorphism, as the actual function to be executed is dynamically determined as per the type of Object at runtime.

Using pointers/references to the base class or virtual functions, we could achieve polymorphic behaviour, where different objects of derived classes can be treated uniformly through the base class interface, allowing for code reusability and flexibility.

Mistakes to be avoided while using Polymorphism

When working with Polymorphism in OOP, you need to avoid certain things to ensure correct and effective usage. Following are some i the common mistake that are to be avoided:

  • Improper method overloading: In method overloading, we define multiple methods with the same name but provide different parameters lists within a single class. Overloading the methods in superclass and its subclass  will lead to unintended method resolution and confusion.
  • Inconsistent method signatures: When you are implementing polymorphism through method overriding, it is very important to ensure that the method Signatures like name, parameters and return type are consistent across the superclass and its subclasses. If you fail to maintain consistency it may lead to compilation errors and incorrect method resolution at the runtime.
  • Failing to cast References: If we fail to perform cast properly, it will result in ClasscastException at the runtime. This is in case if we use a superclass reference to hold an object of the subclass, we need to downcast the reference to that particular subclass type to access subclass-specific methods or properties.
  • Neglecting to override methods: It is very important to override the relevant methods in the subclasses. If we neglect to override a method in the subclass, it may result in the superclass method being invoked instead, leading to incomplete implementation/unexpected behaviour.
  • No proper reference type: To benefit from polymorphism, it is important to use reference variables of the suitable abstract/superclass type. Using a particular subclass reference will limit the ability to treat the objects of different subclasses uniformly.  So to ensure polymorphism behaviour, it is important to use the common interface or the superclass reference. 
  • Modifying Polymorphic Objects unexpectedly: If we modify the state of a Polymorphics object through a reference, it can have unintended consequences if the same object is accessed through another reference. So we need to understand the implications of modifying shared objects and ensure proper encapsulation and management of object state.

By keeping in mind all these things you can follow the best practices and use polymorphism effectively in Object oriented programming. 

Java Certification Training

Weekday / Weekend Batches

Conclusion: 

In this blog, we have learned what is Polymorphism in Object oriented programming, why is polymorphism used, Types of Polymorphism with examples and mistakes to be avoided while implementing polymorphism. We hope you found the information helpful. For more blogs related to Object Oriented Programming, stay tuned to HKR Trainings.

Related Article:

Find our upcoming Java Certification Training Online Classes

  • Batch starts on 28th Sep 2023, Weekday batch

  • Batch starts on 2nd Oct 2023, Weekday batch

  • Batch starts on 6th Oct 2023, Fast Track batch

Global Promotional Image
 

Categories

Request for more information

Amani
Amani
Research Analyst
As a content writer at HKR trainings, I deliver content on various technologies. I hold my graduation degree in Information technology. I am passionate about helping people understand technology-related content through my easily digestible content. My writings include Data Science, Machine Learning, Artificial Intelligence, Python, Salesforce, Servicenow and etc.

.