Polymorphism means having many forms. It is a key concept in object-oriented programming (OOP) that allows objects of different types to be treated as objects of a common base type. It enables you to write code that can work with objects in a generalized manner, providing flexibility and extensibility to your programs. This allows us to perform a single action in different ways.
Polymorphism is achieved through two main mechanisms in C++: compile-time polymorphism (static polymorphism) and runtime polymorphism (dynamic polymorphism).
1. Compile-Time Polymorphism (Static Polymorphism):
Compile-time polymorphism is achieved through function overloading and operator overloading. Function overloading allows you to define multiple functions with the same name but different parameters. The appropriate function is selected based on the arguments at compile time. Operator overloading allows you to redefine the behavior of operators for user-defined types.
Example of function overloading:
int add(int a, int b)
{
return a + b;
}
double add(double a, double b)
{
return a + b;
}
In this example, the `add` function is overloaded to handle both integer and floating-point arguments. The appropriate version of the function is selected based on the argument types at compile time.
2. Runtime Polymorphism (Dynamic Polymorphism):
Runtime polymorphism is achieved through inheritance (function overriding) and virtual functions. Inheritance allows you to create a hierarchy of classes, where derived classes inherit properties and behaviors from their base classes.
Virtual Functions:
Syntax:
To declare a virtual function, you use the `virtual` keyword in the function declaration in the base class. Derived classes that want to override the virtual function must use the `override` keyword to indicate their intent.
Example of virtual function:
class Animal
{
public:
virtual void makeSound()
{
cout << "Animal makes a sound" << endl;
}
};
class Dog : public Animal
{
public:
void makeSound() override
{
cout << "Dog barks" << endl;
}
};
class Cat : public Animal
{
public:
void makeSound() override
{
cout << "Cat meows" << endl;
}
};
int main()
{
Animal* animalPtr;
Dog dog;
Cat cat;
animalPtr = &dog;
animalPtr->makeSound(); // Output: Dog barks
animalPtr = &cat;
animalPtr->makeSound(); // Output: Cat meows
animalPtr->Animal::makeSound(); // This will call virtual function
return 0;
}
In this example, we have a base class `Animal` and two derived classes `Dog` and `Cat`. Each derived class overrides the `makeSound()` function of the base class. By using a pointer to the base class, we can dynamically switch between different derived class objects and invoke the appropriate `makeSound()` function at runtime.