Unit 4 - Polymorphism
Polymorphism and Its Types in C++
1️⃣ What is Polymorphism?
Polymorphism means "one interface, multiple implementations."
It allows a function, operator, or object to take different forms in different
situations.
Example:
class Animal {
public:
virtual void sound() { cout << "Animal makes a sound"; }
};
class Dog : public Animal {
public:
void sound() { cout << "Dog barks"; }
};
Here, both Animal and Dog have a sound() function, but it behaves differently
depending on the object.
2️⃣ Types of Polymorphism in C++
C++ supports two main types of polymorphism:
1. Compile-time Polymorphism (Static Binding)
2. Run-time Polymorphism (Dynamic Binding)
3️⃣ Compile-time Polymorphism (Early Binding) 📌
Decided at compile time.
Unit 4 - Polymorphism 1
Faster execution as it resolves the function call during compilation.
Implemented using:
Function Overloading
Operator Overloading
(i) Function Overloading
Multiple functions with the same name but different parameters.
The compiler decides which function to call based on arguments.
Example:
#include <iostream>
using namespace std;
class Math {
public:
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }
};
int main() {
Math obj;
cout << obj.add(5, 3) << endl; // Calls int add()
cout << obj.add(2.5, 3.5) << endl; // Calls double add()
}
Output:
8
6
(ii) Operator Overloading
Unit 4 - Polymorphism 2
Allows operators to work with user-defined types.
Example: Overloading + for adding two objects.
Example:
#include <iostream>
using namespace std;
class Complex {
public:
int real, imag;
Complex(int r, int i) : real(r), imag(i) {}
Complex operator+(Complex c) {
return Complex(real + c.real, imag + c.imag);
}
void display() { cout << real << " + " << imag << "i" << endl; }
};
int main() {
Complex c1(3, 4), c2(1, 2);
Complex c3 = c1 + c2;
c3.display();
}
Output:
4 + 6i
4️⃣ Run-time Polymorphism (Late Binding) 🔄
Decided at runtime.
Unit 4 - Polymorphism 3
Uses pointers and base class references.
Implemented using:
Function Overriding
Virtual Functions
(i) Function Overriding
Same function name in both parent and child class.
Base class pointer calls derived class function.
Achieved using virtual functions.
Example:
#include <iostream>
using namespace std;
class Base {
public:
virtual void show() { cout << "Base class" << endl; }
};
class Derived : public Base {
public:
void show() { cout << "Derived class" << endl; }
};
int main() {
Base* ptr;
Derived obj;
ptr = &obj;
ptr->show(); // Calls Derived class show()
}
Output:
Derived class
Unit 4 - Polymorphism 4
5️⃣Polymorphism
Differences Between Compile-time & Run-time
Feature Compile-time Polymorphism Run-time Polymorphism
Binding Time At Compile-time At Run-time
Speed Faster Slower
Function Overloading, Operator Function Overriding, Virtual
Implementation
Overloading Functions
Flexibility Less flexible More flexible
6️⃣ Benefits of Polymorphism
✅ Code Reusability – One function works for multiple cases.
✅ Maintainability – Easier to update code.
✅ Scalability – Helps build large applications efficiently.
✅ Extensibility – Easily add new functionalities.
7️⃣ Conclusion
Polymorphism is a key concept in Object-Oriented Programming that makes
code more flexible, reusable, and maintainable.
Dynamic Binding in C++
1️⃣ What is Dynamic Binding?
Dynamic binding (also called late binding or runtime polymorphism) means
that the method to be executed is determined at runtime, not at compile-time.
It is implemented using virtual functions and pointers in C++.
2️⃣ How Dynamic Binding Works?
Unit 4 - Polymorphism 5
When a base class pointer is used to refer to a derived class object, the
function that gets executed depends on the actual object type at runtime,
not the pointer type.
Virtual functions enable dynamic binding.
3️⃣Overriding
Example of Dynamic Binding (Function
with Virtual Functions)
#include <iostream>
using namespace std;
class Base {
public:
virtual void show() { // Virtual function enables dynamic binding
cout << "Base class function" << endl;
}
};
class Derived : public Base {
public:
void show() override { // Function overriding
cout << "Derived class function" << endl;
}
};
int main() {
Base* ptr; // Base class pointer
Derived obj; // Derived class object
ptr = &obj; // Base class pointer pointing to Derived class object
ptr->show(); // Calls Derived class function due to dynamic binding
}
🔹 Output:
Unit 4 - Polymorphism 6
Derived class function
✅ Here, even though is a Base class pointer, it calls
ptr Derived::show() because
of dynamic binding enabled by the virtual keyword.
4️⃣Binding
Differences Between Static Binding & Dynamic
Feature Static Binding Dynamic Binding
Binding Time Compile-time Run-time
Speed Faster Slower
Function Overloading, Operator Function Overriding, Virtual
Implementation
Overloading Functions
Flexibility Less flexible More flexible
Large applications with
Use Case Small programs, fixed function calls
polymorphism
5️⃣ Why Use Dynamic Binding?
✔ Code Reusability – Base class pointers can call derived class methods
dynamically.
✔ Extensibility – Easy to add new derived classes without modifying base
class code.
✔ Flexibility – Function calls are resolved at runtime, allowing dynamic
behavior.
6️⃣ Conclusion
Dynamic binding is an essential feature of object-oriented programming that
allows for polymorphism and makes programs more flexible and extensible.
Friend Function in C++
Unit 4 - Polymorphism 7
1️⃣ What is a Friend Function?
A friend function is a special function that can access private and protected
members of a class, even though it is not a member of that class.
It is declared inside the class using the friend keyword but defined outside the
class.
2️⃣ Why Use a Friend Function?
✔ To access private data of a class without using getter functions.
✔ To allow external functions (non-member functions) to interact with class
data.
✔ Useful in operator overloading when we need to work with private class
members.
3️⃣ Syntax of Friend Function
class ClassName {
friend returnType FunctionName(parameters);
};
📌 The friend function is declared inside the class but defined outside the
class.
4️⃣ Example of Friend Function
#include <iostream>
using namespace std;
class Box {
private:
int length;
public:
Box() : length(10) {} // Constructor to initialize length
Unit 4 - Polymorphism 8
// Friend function declaration
friend void printLength(Box b);
};
// Friend function definition (not a member of class)
void printLength(Box b) {
cout << "Length of the box: " << b.length << endl;
}
int main() {
Box obj;
printLength(obj); // Calling friend function
return 0;
}
🔹 Output:
Length of the box: 10
✅ Here, printLength() is a friend function that can access the private member
length of the Box class.
5️⃣ Characteristics of Friend Functions
✔ Declared inside the class but defined outside it.
✔ Not a member function of the class.
✔ Can access private and protected members of the class.
✔ Must be explicitly granted access using the keyword. friend
✔ Cannot be called using class objects (called normally like regular
functions).
6️⃣ Friend Function with Multiple Classes
Unit 4 - Polymorphism 9
A friend function can be used to access private data of multiple classes.
#include <iostream>
using namespace std;
class ClassB; // Forward declaration
class ClassA {
private:
int numA;
public:
ClassA() : numA(5) {}
friend void showData(ClassA, ClassB); // Friend function
};
class ClassB {
private:
int numB;
public:
ClassB() : numB(10) {}
friend void showData(ClassA, ClassB); // Friend function
};
// Friend function definition
void showData(ClassA a, ClassB b) {
cout << "Sum of numbers: " << a.numA + b.numB << endl;
}
int main() {
ClassA objA;
ClassB objB;
showData(objA, objB);
return 0;
}
Unit 4 - Polymorphism 10
🔹 Output:
Sum of numbers: 15
✅ Here, showData() is a friend function that accesses private data of both ClassA
and ClassB .
7️⃣ Advantages of Friend Functions
✔ Can access private and protected members directly.
✔ Helps in operator overloading.
✔ Useful when two classes need to share private data.
8️⃣ Disadvantages of Friend Functions
❌ Breaks encapsulation by accessing private members.
❌ Less secure as it exposes private data.
❌ Increases coupling between classes, making maintenance harder.
9️⃣ When to Use a Friend Function?
✔ When two or more classes need to share private data.
✔ When operator overloading requires access to private members.
✔ When we want non-member functions to interact with class data.
🔟 Conclusion
A friend function is a powerful feature in C++ that allows non-member
functions to access private class data, but it should be used carefully to
maintain encapsulation.
Overloading and Overriding in C++
Unit 4 - Polymorphism 11
1️⃣ What is Overloading?
🔹 Overloading is a feature in C++ where multiple functions or operators have
the same name but different parameters or implementations.
🔹 It helps in making the code more readable and reusable.
🔹 Types of Overloading:
Function Overloading
Operator Overloading
2️⃣ Function Overloading
🔹 When multiple functions have the same name but different parameters, it is
called function overloading.
🔹 The compiler determines which function to execute based on function
signature (number and type of parameters).
✅ Example of Function Overloading:
#include <iostream>
using namespace std;
class Math {
public:
// Function to add two integers
int add(int a, int b) {
return a + b;
}
// Function to add three integers (same name, different parameters)
int add(int a, int b, int c) {
return a + b + c;
}
// Function to add two floating-point numbers
double add(double a, double b) {
return a + b;
Unit 4 - Polymorphism 12
}
};
int main() {
Math obj;
cout << "Sum (int): " << obj.add(5, 10) << endl;
cout << "Sum (int, int, int): " << obj.add(5, 10, 15) << endl;
cout << "Sum (double): " << obj.add(5.5, 10.2) << endl;
return 0;
}
🔹 Output:
Sum (int): 15
Sum (int, int, int): 30
Sum (double): 15.7
✅ The add function is overloaded with different parameters.
3️⃣ Operator Overloading
🔹 Allows us to redefine operators ( , , , etc.) to work with user-defined
+ - *
data types (like objects).
🔹 Example: Overloading the operator to add two objects.
+
✅ Example of Operator Overloading:
#include <iostream>
using namespace std;
class Complex {
public:
int real, imag;
Unit 4 - Polymorphism 13
Complex(int r, int i) : real(r), imag(i) {}
// Overloading + operator
Complex operator+(Complex obj) {
return Complex(real + obj.real, imag + obj.imag);
}
void display() {
cout << real << " + " << imag << "i" << endl;
}
};
int main() {
Complex c1(3, 5), c2(2, 4);
Complex c3 = c1 + c2; // Calls overloaded + operator
c3.display();
return 0;
}
🔹 Output:
5 + 9i
✅ The + operator is overloaded to work with Complex objects.
4️⃣ What is Overriding?
🔹 Overriding occurs when a child class provides a specific implementation
of a function that is already defined in its base (parent) class.
🔹 The function must have the same name and same parameters.
🔹 It is used in inheritance to modify the behavior of a function in the derived
class.
🔹 The base class function must be declared as for proper overriding.
virtual
Unit 4 - Polymorphism 14
✅ Example of Function Overriding:
#include <iostream>
using namespace std;
class Animal {
public:
// Base class function
virtual void makeSound() {
cout << "Animal makes a sound" << endl;
}
};
class Dog : public Animal {
public:
// Overriding makeSound function
void makeSound() override {
cout << "Dog barks" << endl;
}
};
int main() {
Animal* obj;
Dog d;
obj = &d;
obj->makeSound(); // Calls Dog's overridden function
return 0;
}
🔹 Output:
Dog barks
Unit 4 - Polymorphism 15
✅ The makeSound() function in Dog overrides the one in Animal .
5️⃣ Differences Between Overloading and Overriding
Feature Overloading Overriding
Multiple functions with same Child class function redefines
Definition
name but different parameters parent class function
Where it
Same class Different classes (Inheritance)
Happens?
Function
Must be different Must be same
Signature?
Must be same (except with
Return Type? Can be different
covariant return types)
Inheritance
Required?
❌ Not required ✅ Required
virtual (for base class
Keyword Used? No special keyword required
function)
Function overloading, operator Overriding a method in child
Example
overloading class
6️⃣ Conclusion
✔ Overloading allows multiple functions/operators with the same name but
different parameters.
✔ Overriding allows modifying inherited functions in a child class.
✔ Overloading works in the same class, while overriding requires
inheritance.
✔ Overriding requires virtual functions, but overloading does not.
Both are essential concepts for writing efficient and flexible OOP code!
Inline Functions in C++
1️⃣ What is an Inline Function?
Unit 4 - Polymorphism 16
🔹 An inline function is a function that is expanded in place where it is called,
instead of executing a separate function call.
🔹 This helps in reducing function call overhead and improves execution
speed.
🔹 The keyword is used before the function definition to suggest the
inline
compiler to make it inline.
2️⃣ Features of Inline Functions
✅ Reduces function call overhead – No need to jump to another memory
location.
✅ Faster execution – Function code is directly inserted into the calling place.
✅ Useful for small functions – Best suited for functions with few lines of
code.
✅ Defined inside the class – Functions defined inside a class are automatically
inline.
✅ Cannot use recursion – Recursive functions cannot be inline as they would
lead to infinite expansion.
3️⃣ Syntax of an Inline Function
inline return_type function_name(parameters) {
// Function body
}
4️⃣ Example of an Inline Function
#include <iostream>
using namespace std;
// Inline function definition
inline int square(int x) {
Unit 4 - Polymorphism 17
return x * x;
}
int main() {
cout << "Square of 5: " << square(5) << endl;
cout << "Square of 10: " << square(10) << endl;
return 0;
}
🔹 Output:
Square of 5: 25
Square of 10: 100
✅ The function square() is inline wherever it is called.
5️⃣ Inline Functions in a Class
🔹 When a function is defined inside a class, it is automatically considered
inline by the compiler.
✅ Example:
#include <iostream>
using namespace std;
class Math {
public:
// Inline function inside a class
int cube(int x) {
return x * x * x;
}
};
int main() {
Unit 4 - Polymorphism 18
Math obj;
cout << "Cube of 3: " << obj.cube(3) << endl;
return 0;
}
🔹 Output:
Cube of 3: 27
✅ Since cube() is inside the class, the compiler treats it as an inline function.
6️⃣ When to Use Inline Functions?
✅ Best for short functions (1-3 lines of code)
✅ For frequently called functions to reduce function call overhead
✅ For performance optimization in time-critical programs
7️⃣ When NOT to Use Inline Functions?
❌ When the function contains loops, switch statements, or recursion
❌ If the function has static variables
❌ If the function is large, as it increases code size instead of optimizing it
8️⃣ Conclusion
✔ Inline functions improve performance by removing function call overhead.
✔ They work best for small functions and class methods.
✔ Avoid inlining large or complex functions, as it can increase memory
usage.
✔ Use wisely to balance performance and memory efficiency!
Unit 4 - Polymorphism 19
Virtual Functions in C++
1️⃣ What is a Virtual Function?
🔹 A virtual function is a function that is declared in a base class and
overridden in a derived class.
🔹 It allows runtime polymorphism by enabling dynamic binding (late binding).
🔹 Declared using the keyword in the base class.
virtual
🔹 Helps in achieving function overriding in inheritance.
2️⃣ Features of Virtual Functions
✅ Supports runtime polymorphism – Function calls are resolved at runtime
instead of compile time.
✅ Declared in the base class and overridden in the derived class.
✅ Ensures correct function call when using base class pointers.
✅ Uses dynamic binding (late binding) instead of static binding.
✅ Must be defined in the base class, even if it has no implementation.
✅ Virtual functions are accessed through pointers or references of the base
class.
3️⃣ Syntax of a Virtual Function
class Base {
public:
virtual void display() { // Virtual function
cout << "Base class display function" << endl;
}
};
4️⃣ Example of Virtual Functions
Unit 4 - Polymorphism 20
Without Virtual Function (Static Binding)
#include <iostream>
using namespace std;
class Base {
public:
void display() { // No virtual keyword
cout << "Base class display function" << endl;
}
};
class Derived : public Base {
public:
void display() {
cout << "Derived class display function" << endl;
}
};
int main() {
Base* ptr;
Derived obj;
ptr = &obj;
ptr->display(); // Calls Base class function (static binding)
return 0;
}
🔹 Output:
Base class display function
🔴 Even though points to a
ptr Derived object, Base class function is called
because of static binding.
Unit 4 - Polymorphism 21
With Virtual Function (Dynamic Binding)
#include <iostream>
using namespace std;
class Base {
public:
virtual void display() { // Virtual function
cout << "Base class display function" << endl;
}
};
class Derived : public Base {
public:
void display() override { // Overriding function
cout << "Derived class display function" << endl;
}
};
int main() {
Base* ptr;
Derived obj;
ptr = &obj;
ptr->display(); // Calls Derived class function (dynamic binding)
return 0;
}
🔹 Output:
Derived class display function
✅ With virtual keyword, the derived class function is called at runtime!
Unit 4 - Polymorphism 22
5️⃣ How Virtual Functions Work?
🔹 When a class has a virtual function, the compiler creates a Virtual Table (V-
Table).
🔹 A pointer called Virtual Table Pointer (V-Ptr) is added to every object of the
class.
🔹 At runtime, this pointer is used to determine which function to call (Base or
Derived).
6️⃣ Rules for Virtual Functions
✅ Must be defined in the base class.
✅ If a derived class does not override the virtual function, the base class
version is used.
✅ Virtual functions must be accessed through a pointer or reference.
✅ Constructors cannot be virtual, but destructors should be virtual in base
classes.
✅ A class with at least one virtual function has a V-Table for dynamic
dispatching.
7️⃣ Virtual Destructor Example
🔹 Why use a virtual destructor?
If a base class destructor is not virtual, destroying a derived class object
through a base class pointer may lead to memory leaks.
✅ Example:
#include <iostream>
using namespace std;
class Base {
public:
Base() { cout << "Base Constructor\n"; }
virtual ~Base() { cout << "Base Destructor\n"; } // Virtual destructor
Unit 4 - Polymorphism 23
};
class Derived : public Base {
public:
Derived() { cout << "Derived Constructor\n"; }
~Derived() { cout << "Derived Destructor\n"; }
};
int main() {
Base* ptr = new Derived();
delete ptr; // Calls both base and derived destructors
return 0;
}
🔹 Output:
Base Constructor
Derived Constructor
Derived Destructor
Base Destructor
✅ Ensures proper cleanup of derived class objects!
8️⃣ When to Use Virtual Functions?
✔ When function overriding is needed in inheritance.
✔ When base class pointers are used to call derived class functions.
✔ When runtime polymorphism is required for flexible design.
✔ When ensuring correct destructor calls in inheritance.
9️⃣ When NOT to Use Virtual Functions?
❌ If the function does not need overriding.
❌ If performance is critical, as virtual functions introduce overhead.
Unit 4 - Polymorphism 24
❌ If object slicing is required (when using value-based function calls).
🔟 Conclusion
✔ Virtual functions enable dynamic binding, ensuring the correct function is
called at runtime.
✔ They are crucial for polymorphism and function overriding.
✔ Use virtual destructors to prevent memory leaks in inheritance.
✔ Avoid virtual functions when not needed, as they introduce slight overhead.
Unit 4 - Polymorphism 25