For working professionals
For fresh graduates
More
4. C++ Variable
10. C++ for Loop
12. C++ Lambda
13. Loop in C++
15. Array in C++
16. Strings in C++
17. Substring in C++
29. Vector in C++
30. Map in C++
31. Pair in C++
33. Iterators in C++
34. Queue in C++
36. Stack in C++
37. ifstream in C++
40. Templates in C++
43. Namespace in C++
46. Recursion in C++
48. C++ Shell
49. Setw in C++
51. Atoi in C++
54. C# vs C++
55. C++ GUI
56. C++ Game Code
57. Class in C++
58. C++ Header Files
63. Cin in C++
64. Printf in C++
65. Struct in C++
66. C++ List
68. C++ Comments
72. Sorting in C++
Object-oriented programming (OOP) offers powerful ways to make our code more adaptable and reusable. Polymorphism is a key concept in OOP that allows us to write code that gracefully handles objects of different types.
The word itself, derived from Greek, means "many forms." In essence, polymorphism lets objects or functions take on multiple behaviors, enhancing code flexibility and adaptability. Think of it as the ability to give a single instruction ("draw yourself") to a variety of shapes, and each shape knows how to respond correctly.
In this tutorial, I will delve into the foundations of polymorphism in C++. With the help of this guide and some examples, I will help you write cleaner, more flexible, and easier-to-maintain code.
Imagine a scenario where you have a variety of shapes: circles, squares, and triangles. Polymorphism would allow you to define a general function called calculateArea(). You could then use this single function to find the area of any shape, regardless of its specific type.
The beauty of polymorphism is that the code doesn't need to know the exact shape it's dealing with at the time it's written. This makes your programs more versatile and easier to maintain.
There are two primary types of polymorphism in C plus plus:
Code:
#include <iostream> // Header for input/output functions (cin, cout, endl)
using namespace std; // Avoids repeatedly using std:: before standard library elements
void print(int num) { // Function definition with integer parameter
cout << "Integer: " << num << endl;
}
void print(double decimal) { // Function definition with double parameter
cout << "Double: " << decimal << endl;
}
int main() { // Main function, program execution starts here
print(5); // Calls print(int) with integer argument (5)
print(3.14); // Calls print(double) with double argument (3.14)
return 0; // Indicates successful program termination
}
This example presents function overloading. We have two functions called print, each taking a different parameter type (one for integers, one for doubles). At compile time, C++ automatically determines which print function to call based on the type of argument you pass.
Code:
#include <iostream>
using namespace std;
class Complex { // Class definition for complex numbers
public:
double real;
double imag;
Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {} // Constructor with default arguments
Complex operator+(const Complex &other) { // Overloaded + operator
return Complex(real + other.real, imag + other.imag);
}
};
int main() {
Complex c1(2, 3); // Creates a Complex object with real = 2, imag = 3
Complex c2(1, 4); // Creates another Complex object
Complex result = c1 + c2; // Uses the overloaded + operator
cout << "Result: " << result.real << " + " << result.imag << "i" << endl;
return 0;
}
Operator overloading lets us redefine how built-in operators work with our custom classes. Here, + is overloaded for Complex objects. This means we can add Complex numbers with natural syntax (e.g., c1 + c2).
Code:
#include <iostream>
#include <cmath> // For mathematical functions like PI
using namespace std;
class Shape {
public:
virtual double calculateArea() = 0;
};
class Circle : public Shape {
private: // Consider making radius a private member
double radius;
public:
Circle(double r) : radius(r) {} // Constructor to set circle's radius
double calculateArea() override {
return M_PI * radius * radius; // M_PI is a constant representing pi
}
};
class Rectangle : public Shape {
private: // Consider making these private members
double width, height;
public:
Rectangle(double w, double h) : width(w), height(h) {} // Constructor
double calculateArea() override {
return width * height;
}
};
int main() {
Shape *shape; // Declare a base class pointer
Circle circle(5); // Create a circle object
shape = &circle;
cout << "Area of circle: " << shape->calculateArea() << endl;
Rectangle rectangle(3, 4); // Create a rectangle object
shape = &rectangle;
cout << "Area of rectangle: " << shape->calculateArea() << endl;
return 0;
}
In the above code, I have included <cmath> for mathematical constants like M_PI. The Shape class defines a pure virtual function calculateArea(), making it an abstract base class that outlines the behavior for derived shapes.
Both Circle and Rectangle inherit from Shape and override calculateArea(), providing specific implementations for calculating the area of their respective shapes. In main, a Shape pointer is used. It can point to either a Circle or a Rectangle object, demonstrating polymorphism. Calling calculateArea() through this pointer dynamically selects the correct implementation at runtime.
Templates provide a way to create generic functions and classes that work with various data types, enabling compile-time polymorphism. Here's an example combining templates and inheritance:
Code:
#include <iostream>
using namespace std;
template <typename T>
class Shape {
public:
virtual void draw() = 0;
};
template <typename T>
class Circle : public Shape<T> {
public:
void draw() override {
cout << "Drawing a Circle" << endl;
}
};
template <typename T>
class Rectangle : public Shape<T> {
public:
void draw() override {
cout << "Drawing a Rectangle" << endl;
}
};
int main() {
Shape<int>* shape1 = new Circle<int>();
Shape<double>* shape2 = new Rectangle<double>();
shape1->draw(); // Outputs: Drawing a Circle
shape2->draw(); // Outputs: Drawing a Rectangle
delete shape1;
delete shape2;
return 0;
}
In this code, we define templated Shape, Circle, and Rectangle classes. The Shape class acts as an abstract base class with a pure virtual draw() function. In main, we create pointers of type Shape<int> and Shape<double>, demonstrating that the templates can work with different data types. Polymorphism works similarly, the draw() functions are dispatched dynamically based on the actual object type.
CRTP (Curiously Recurring Template Pattern) is a technique that allows compile-time polymorphism while achieving a form of static inheritance. Let's see an example:
Code:
#include <iostream>
#include <string>
template <typename Derived>
class Printable {
public:
void print() {
static_cast<Derived*>(this)->printDetails();
}
};
class Person : public Printable<Person> {
private:
std::string name;
int age;
public:
Person(const std::string& n, int a) : name(n), age(a) {}
void printDetails() {
std::cout << "Name: " << name << ", Age: " << age << std::endl;
}
};
class Product : public Printable<Product> {
private:
std::string description;
double price;
public:
Product(const std::string& desc, double p) : description(desc), price(p) {}
void printDetails() {
std::cout << "Description: " << description << ", Price: $" << price << std::endl;
}
};
int main() {
Person john("John Doe", 35);
Product book("The C++ Guide", 24.99);
john.print(); // Output: Name: John Doe, Age: 35
book.print(); // Output: Description: The C++ Guide, Price: $24.99
return 0;
}
In this code, the Printable class acts like an interface using the CRTP technique, forcing derived classes to implement printDetails(). Person and Product can implement their unique printing behavior and the print() function in Printable provides a uniform way to print any derived type.
Code:
#include <iostream>
using namespace std;
class Shape {
public:
virtual void draw() {
cout << "Generic Shape" << endl;
}
};
class Colored {
public:
virtual void showColor() {
cout << "Generic Color" << endl;
}
};
class ColoredCircle : public Shape, public Colored {
public:
void draw() override {
cout << "Drawing a Colored Circle" << endl;
}
void showColor() override {
cout << "Color of the Circle" << endl;
}
};
int main() {
ColoredCircle coloredCircle;
coloredCircle.draw(); // Outputs: Drawing a Colored Circle
coloredCircle.showColor(); // Outputs: Color of the Circle
return 0;
}
In the above code, Shape and Colored are base classes with virtual functions. ColoredCircle inherits from both Shape and Colored, getting the capabilities of both. ColoredCircle overrides both draw() and showColor(), providing specialized behavior.
If both base classes were to have functions with the same name and signature without being virtual, ColoredCircle would face ambiguity. Using virtual is essential in multiple inheritance scenarios.
If you wish to master C++, you can enroll in one of upGrad’s software engineering courses.
Here are the key advantages of polymorphism in C++:
According to me, polymorphism is a potent tool in the C++ programmer's arsenal. By understanding compile-time and runtime polymorphism, I believe that you'll write more flexible, adaptable, and elegant object-oriented code.
If you wish to become a master of C++ and concepts such as as polymorphism in C++, you can enrol yourself in one of upGrad’s software engineering programs.
1. What is a polymorphism in C++?
Polymorphism in C++ is the ability of objects of different types to respond differently to the same method or function call. This is primarily achieved through inheritance, virtual functions, and function overloading.
2. What is polymorphism and its example?
Polymorphism means "many forms." An example would be a Shape base class with derived classes like Circle, Triangle, and Rectangle. All shapes could have a calculateArea() method, but each subclass implements the calculation uniquely.
3. What is polymorphism in C programming?
C doesn't directly support object-oriented polymorphism. However, you can achieve a limited form of polymorphism using function pointers and carefully designed function signatures.
4. What is polymorphism in compiler design?
In compiler design, polymorphism often arises in the context of type systems and name resolution. A compiler needs to polymorphically determine the correct type and meaning of an operator or function call based on the types of the arguments involved.
5. Where is polymorphism used in C++?
Polymorphism in C++ is used widely to:
6. What is polymorphism data in OOP?
There's no specific term called "polymorphism data" in OOP. Polymorphism is primarily about how functions or methods behave differently based on the object's type, not the data itself.
Author
Start Learning For Free
Explore Our Free Software Tutorials and Elevate your Career.
Talk to our experts. We are available 7 days a week, 9 AM to 12 AM (midnight)
Indian Nationals
1800 210 2020
Foreign Nationals
+918068792934
1.The above statistics depend on various factors and individual results may vary. Past performance is no guarantee of future results.
2.The student assumes full responsibility for all expenses associated with visas, travel, & related costs. upGrad does not provide any a.