codingstuff.io
ExploreTutorialsProblemsCS Subjects
Get Started
ExploreTutorialsProblemsCS Subjects
Get Started
codingstuff.io

Master the art of building software through interactive tutorials, real-world problems, and guided projects.

Pune, Maharashtra, India

codingstuffmail@gmail.com

Product

  • Explore
  • Tutorials
  • Problems
  • CS Subjects

Company

  • About
  • Contact
  • Privacy Policy
  • Terms & Conditions
  • Sitemap

© 2026 codingstuff.io. All rights reserved.

Built with ❤️ for developers everywhere

/
/
All Tutorials
⚡

C++ Programming

51 / 87 topics
48Inheritance Basics49Public, Protected, and Private Inheritance50Types of Inheritance51Polymorphism52Function Overriding53Virtual Functions54Abstract Class and Pure Virtual Function
Tutorials/C++ Programming/Polymorphism
⚡C++ Programming

Polymorphism

Updated 2026-05-12
30 min read

Polymorphism

Polymorphism is a fundamental concept in object-oriented programming (OOP) that allows objects to be treated as instances of their parent class. It enables a single interface to represent different underlying forms (data types). In C++, polymorphism can be achieved through two main mechanisms: compile-time polymorphism and runtime polymorphism.

Introduction

Polymorphism is crucial in OOP because it promotes code reusability, flexibility, and scalability. By allowing objects of different classes to be treated as objects of a common superclass, polymorphism helps in writing more generic and maintainable code. This tutorial will explore both compile-time and runtime polymorphism, along with the concept of upcasting.

Compile-Time Polymorphism

Compile-time polymorphism is achieved through function overloading and operator overloading. It occurs when multiple functions have the same name but different parameters within the same class or derived classes. The compiler decides which function to call at compile time based on the arguments passed.

Function Overloading

Function overloading allows a class to have more than one function with the same name, as long as their parameter lists are different. This is useful when you want to perform similar operations in slightly different ways.

function_overloading.cpp
1#include <iostream>
2
3class Calculator {
4public:
5 int add(int a, int b) {
6 return a + b;
7 }
8
9 double add(double a, double b) {
10 return a + b;
11 }
12};
13
14int main() {
15 Calculator calc;
16 std::cout << "Adding integers: " << calc.add(5, 3) << std::endl;
17 std::cout << "Adding doubles: " << calc.add(5.5, 3.2) << std::endl;
18 return 0;
19}
Output
Adding integers: 8
Adding doubles: 8.7

In this example, the Calculator class has two overloaded versions of the add function. The first version takes two integers and returns their sum, while the second version takes two doubles and returns their sum. The compiler determines which function to call based on the arguments passed.

Operator Overloading

Operator overloading allows you to redefine the behavior of operators for user-defined types. This can make your code more intuitive and easier to read.

operator_overloading.cpp
1#include <iostream>
2
3class Complex {
4private:
5 double real;
6 double imag;
7
8public:
9 Complex(double r = 0, double i = 0) : real(r), imag(i) {}
10
11 Complex operator+(const Complex& other) const {
12 return Complex(real + other.real, imag + other.imag);
13 }
14
15 void display() const {
16 std::cout << real << " + " << imag << "i" << std::endl;
17 }
18};
19
20int main() {
21 Complex c1(3.0, 4.0);
22 Complex c2(1.5, 2.5);
23 Complex c3 = c1 + c2;
24 c3.display();
25 return 0;
26}
Output
4.5 + 6.5i

Here, the + operator is overloaded for the Complex class to add two complex numbers. The operator+ function takes another Complex object as a parameter and returns a new Complex object representing their sum.

Runtime Polymorphism

Runtime polymorphism is achieved through function overriding. It occurs when a derived class provides a specific implementation of a function that is already defined in its base class. This allows the program to decide at runtime which function to call based on the actual object type.

Function Overriding

Function overriding involves defining a function in the derived class with the same name, return type, and parameters as a function in the base class. The virtual keyword is used in the base class to indicate that the function can be overridden by derived classes.

function_overriding.cpp
1#include <iostream>
2
3class Animal {
4public:
5 virtual void speak() const {
6 std::cout << "Some generic animal sound" << std::endl;
7 }
8};
9
10class Dog : public Animal {
11public:
12 void speak() const override {
13 std::cout << "Woof!" << std::endl;
14 }
15};
16
17class Cat : public Animal {
18public:
19 void speak() const override {
20 std::cout << "Meow!" << std::endl;
21 }
22};
23
24int main() {
25 Animal* animal1 = new Dog();
26 Animal* animal2 = new Cat();
27
28 animal1->speak(); // Outputs: Woof!
29 animal2->speak(); // Outputs: Meow!
30
31 delete animal1;
32 delete animal2;
33
34 return 0;
35}
Output
Woof!
Meow!

In this example, the Animal class has a virtual function speak(). The Dog and Cat classes override this function to provide specific implementations. When the speak() method is called on pointers of type Animal, the actual object's type determines which version of the function is executed.

Upcasting

Upcasting is the process of converting a pointer or reference from a derived class to its base class. This is allowed in C++ because every derived class object can be treated as an object of its base class.

upcasting.cpp
1#include <iostream>
2
3class Base {
4public:
5 virtual void show() const {
6 std::cout << "Base class show function" << std::endl;
7 }
8};
9
10class Derived : public Base {
11public:
12 void show() const override {
13 std::cout << "Derived class show function" << std::endl;
14 }
15};
16
17int main() {
18 Derived derivedObj;
19 Base* basePtr = &derivedObj; // Upcasting
20
21 basePtr->show(); // Outputs: Derived class show function
22 return 0;
23}
Output
Derived class show function

In this example, a pointer to the Base class is assigned the address of a Derived object. This is an upcast because we are moving from a more specific type (Derived) to a more general type (Base). The virtual function show() in the base class ensures that the derived class's implementation is called.

Practical Example

Let's create a simple program that demonstrates both compile-time and runtime polymorphism, along with upcasting.

polymorphism_example.cpp
1#include <iostream>
2
3class Shape {
4public:
5 virtual void draw() const {
6 std::cout << "Drawing a shape" << std::endl;
7 }
8};
9
10class Circle : public Shape {
11public:
12 void draw() const override {
13 std::cout << "Drawing a circle" << std::endl;
14 }
15};
16
17class Square : public Shape {
18public:
19 void draw() const override {
20 std::cout << "Drawing a square" << std::endl;
21 }
22};
23
24void drawShape(Shape* shape) {
25 shape->draw();
26}
27
28int main() {
29 Circle circle;
30 Square square;
31
32 drawShape(&circle); // Outputs: Drawing a circle
33 drawShape(&square); // Outputs: Drawing a square
34
35 Shape* basePtr = &circle; // Upcasting
36 basePtr->draw(); // Outputs: Drawing a circle
37
38 return 0;
39}
Output
Drawing a circle
Drawing a square
Drawing a circle

In this program, the Shape class is the base class with a virtual function draw(). The Circle and Square classes override this function to provide specific implementations. The drawShape() function takes a pointer to a Shape object and calls its draw() method. This demonstrates runtime polymorphism. Additionally, upcasting is shown when a Circle object's address is assigned to a Shape* pointer.

Summary

ConceptDescription
Compile-time PolymorphismAchieved through function overloading and operator overloading. Decided at compile time.
Runtime PolymorphismAchieved through function overriding. Decided at runtime based on the actual object type.
UpcastingConverting a pointer or reference from a derived class to its base class.

What's Next?

In the next tutorial, we will delve deeper into function overriding, exploring more complex scenarios and best practices. Understanding function overriding is crucial for mastering runtime polymorphism in C++.


PreviousTypes of InheritanceNext Function Overriding

Recommended Gear

Types of InheritanceFunction Overriding