Polymorphism is one of the cornerstones of object-oriented programming (OOP) in C++. It allows objects to be treated as instances of their parent class rather than their actual class. This article will explore the concepts of polymorphism in C++, provide practical examples, and discuss its use cases.
Polymorphism in C++ allows for flexibility and integration in code by enabling functions to use objects of different types through a common interface. This leads to more maintainable and scalable code, as new functionalities can be added with minimal changes to existing code.
What is Polymorphism?
Polymorphism means “many forms.” In C++, it allows functions and operators to be used in different ways, depending on the context. The two primary types of polymorphism in C++ are compile-time (or static) polymorphism and runtime (or dynamic) polymorphism.
Types of Polymorphism in C++
Compile-time Polymorphism
Compile-time polymorphism is achieved through function overloading and operator overloading. This type of polymorphism is resolved during compilation.
- Function Overloading: Multiple functions with the same name but different parameters.
- Operator Overloading: Defining custom behavior for operators.
Runtime Polymorphism
Runtime polymorphism is achieved through inheritance and virtual functions. This type of polymorphism is resolved during runtime.
- Virtual Functions: Functions that can be overridden in derived classes.
- Abstract Classes: Classes that cannot be instantiated and are designed to be subclassed.
Compile-time Polymorphism
Function Overloading
Function overloading allows multiple functions to have the same name with different parameters. The correct function is chosen based on the arguments.
Example of Function Overloading:
- void print(int i) { std::cout << “Printing int: ” << i << std::endl; }
- void print(double f) { std::cout << “Printing float: ” << f << std::endl; }
- void print(std::string s) { std::cout << “Printing string: ” << s << std::endl; }
Operator Overloading
Operator overloading allows you to define the behavior of operators for user-defined types.
Example of Operator Overloading:
- class Complex { public: double real, imag; Complex operator + (const Complex& obj) { Complex res; res.real = real + obj.real; res.imag = imag + obj.imag; return res; } };
Runtime Polymorphism
Virtual Functions
Virtual functions allow derived classes to override methods of the base class.
Example of Virtual Functions:
- class Base { public: virtual void show() { std::cout << “Base class show function called” << std::endl; } };
- class Derived : public Base { public: void show() override { std::cout << “Derived class show function called” << std::endl; } };
Abstract Classes
Abstract classes contain at least one pure virtual function. They cannot be instantiated and are intended to be subclassed.
Example of Abstract Classes:
- class Shape { public: virtual void draw() = 0; // Pure virtual function };
- class Circle : public Shape { public: void draw() override { std::cout << “Drawing Circle” << std::endl; } };
Use Cases of Polymorphism
- Implementing Interfaces: Allows the implementation of interface methods in derived classes.
- Code Reusability: Base class code can be reused with derived class objects.
- Dynamic Method Resolution: Runtime decision of which method to invoke.
- Flexibility and Scalability: Adding new classes with minimal changes to existing code.
Working with C++ Arrays and Polymorphism
Polymorphism can also be used with C++ arrays, particularly arrays of pointers to base class types. This allows arrays to hold objects of different derived classes, all through base class pointers.
Example of Working with C++ Arrays and Polymorphism:
- Shape* shapes[2]; shapes[0] = new Circle(); shapes[1] = new Square();
for (int i = 0; i < 2; ++i) { shapes[i]->draw(); // Calls the draw() method for each object }
Conclusion
Polymorphism in C++ is a powerful feature that enhances the flexibility and maintainability of code. By understanding and using compile-time and runtime polymorphism, developers can create more versatile and efficient applications. Whether you are overloading functions or using virtual functions in a class hierarchy, polymorphism allows for elegant and dynamic code design.