0% found this document useful (0 votes)
5 views33 pages

Module 4b (Polymorphism)

The document covers the concept of polymorphism in C++, including function overloading, operator overloading, and dynamic polymorphism through virtual functions. It explains how to implement these features with examples, detailing the syntax and rules for overloading functions and operators. Additionally, it discusses the importance of virtual functions for achieving runtime polymorphism in derived classes.

Uploaded by

tanjilsajil94
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views33 pages

Module 4b (Polymorphism)

The document covers the concept of polymorphism in C++, including function overloading, operator overloading, and dynamic polymorphism through virtual functions. It explains how to implement these features with examples, detailing the syntax and rules for overloading functions and operators. Additionally, it discusses the importance of virtual functions for achieving runtime polymorphism in derived classes.

Uploaded by

tanjilsajil94
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Module 4b

Polymorphism
Function overloading, Operator overloading, Function overriding in
Dynamic Polymorphism, Virtual functions, Virtual destructors, Pure
virtual functions - Abstract classes.
Polymorphism - having many forms

2
Function Overloading
• Multiple functions can have the same name with different
parameters.
• // same name different arguments
• int test() { }
Overloaded functions may or may not
• void test(int a) { } have different return types but they
• float test(double a) { } must have different arguments.
• int test(int a, double b) { }
// Error code
int test(int a) { }
double test(int b){ }
3
#include <iostream>
using namespace std;
// function with 2 parameters
void display(int var1, double var2) {
cout << "Integer number: " << var1 << " and double number: " << var2 << endl;
}
// function with double type single parameter
void display(double var) { cout << "Double number: " << var << endl; }
// function with int type single parameter
void display(int var) { cout << "Integer number: " << var << endl; }
int main() {
int a = 5;
double b = 5.5;
// call function with int type parameter
display(a);
// call function with double type parameter
display(b);
// call function with 2 parameters
display(a, b);
4
return 0;
Operator Overloading
• Operator overloading in C++ allows you to redefine how operators
work for user-defined types (such as classes and structs).
• Enables arithmetic and logical operations on user-defined types.
• An operator can be overloaded by defining a special function using
the operator keyword. It can be a member function or a non-member
function (friend function).
• Syntax
returnType operator symbol (arguments) {
... .. ...
}
5
• Types of Operator Overloading
• Unary Operator Overloading (e.g., ++, --, -, !)
• Binary Operator Overloading (e.g., +, -, *, /)
• Relational Operator Overloading (e.g., ==, !=, >, <)
• Stream Operator Overloading (<<, >> must be overloaded as friend
functions)

• Some operators cannot be overloaded in C++, such as


• :: (Scope resolution)
• .* (Pointer-to-member access)
• . (Member access)
• sizeof (Size operator)
• Typeid
• ?: (ternary)

6
Operator functions
• Must be either member functions(non-static) or friend functions.

Unary operator Binary operator

Member function No argument One argument

Friend function One argument Two arguments

7
Overloading unary operators – Member functions
#include <iostream> int main() {
using namespace std; Counter obj(5);
class Counter {
int count; cout << "Before increment and decrement:" << endl;
public: [Link]();
// Constructor
Counter(int c = 0) { // Applying overloaded operators
count = c; ++obj; // Calls overloaded ++ operator
} cout << "After Increment: ";
void operator++() {// Overloading unary ++ operator (prefix) [Link]();
++count;
} --obj; // Calls overloaded -- operator
void operator--() {// Overloading unary -- operator (prefix) cout << "After Decrement: ";
--count; [Link]();
}
// Display function return 0;
void show() { }
cout << "Count: " << count << endl;
}
};

8
Overloading unary operators - Friend functions
#include <iostream> // Definition of overloaded ++ operator
using namespace std; void operator++(Counter obj) {
++[Link];
class Counter { }
int count; // Definition of overloaded -- operator
public: void operator--(Counter obj) {
// Constructor --[Link];
Counter(int c = 0) { }
count = c; int main() {
} Counter obj(5);
cout << "Before increment and decrement:" << endl;
// Friend function to overload unary ++ (prefix) [Link]();
friend void operator++(Counter obj); // Applying overloaded operators
++obj; // Calls overloaded ++ operator
// Friend function to overload unary -- (prefix) cout << "After Increment: ";
friend void operator--(Counter obj); [Link]();
--obj; // Calls overloaded -- operator
// Display function cout << "After Decrement: ";
void show() { [Link]();
cout << "Count: " << count << endl; return 0;
} }
}; 9
Overloading unary operators - Friend functions
#include <iostream> // Definition of overloaded ++ operator
using namespace std; void operator++(Counter &obj) {
++[Link];
class Counter { }
int count; // Definition of overloaded -- operator
public: void operator--(Counter &obj) {
// Constructor --[Link];
Counter(int c = 0) { }
count = c; int main() {
} Counter obj(5);
cout << "Before increment and decrement:" << endl;
// Friend function to overload unary ++ (prefix) [Link]();
friend void operator++(Counter &obj); // Applying overloaded operators
++obj; // Calls overloaded ++ operator
// Friend function to overload unary -- (prefix) cout << "After Increment: ";
friend void operator--(Counter &obj); [Link]();
--obj; // Calls overloaded -- operator
// Display function cout << "After Decrement: ";
void show() { [Link]();
cout << "Count: " << count << endl;
} return 0;
}; } 10
Overloading binary operators - Member functions
#include <iostream> int main() {
using namespace std; Complex c1(5, 6), c2(2, 3);
class Complex { cout << "First complex number: ";
int real, imag; [Link]();
public: cout << "Second complex number: ";
Complex(int r = 0, int i = 0) {// Constructor [Link]();
real = r; // Adding two complex numbers using overloaded +
imag = i; Complex sum = c1 + c2;
} cout << "Sum of complex numbers: ";
Complex operator+(Complex obj) {// Overloading binary + [Link]();
Complex temp; // Temporary variable // Subtracting two complex numbers using overloaded -
[Link] = real + [Link]; Complex diff = c1 - c2;
[Link] = imag + [Link]; cout << "Difference of complex numbers: ";
return temp; [Link]();
} return 0;
Complex operator-(Complex obj) {// Overloading binary - }
Complex temp; // Temporary variable
[Link] = real - [Link];
[Link] = imag - [Link];
return temp;
}
void display() { // Display function 11
cout << real << " + " << imag << "i" << endl;
Overloading binary operators - Friend functions
#include <iostream> // Definition of overloaded - operator using friend function
using namespace std; Complex operator-(Complex c1, Complex c2) {
class Complex { Complex temp; // Temporary variable
int real, imag; [Link] = [Link] - [Link];
public: [Link] = [Link] - [Link];
// Constructor return temp;
Complex(int r = 0, int i = 0) { }
real = r; imag = i; } int main() {
// Friend function to overload + operator Complex c1(5, 6), c2(2, 3);
friend Complex operator+(Complex c1, Complex c2); cout << "First complex number: ";
// Friend function to overload - operator [Link]();
friend Complex operator-(Complex c1, Complex c2); cout << "Second complex number: ";
void display() {// Display function [Link]();
cout << real << " + " << imag << "i" << endl; // Adding two complex numbers using overloaded +
} Complex sum = c1 + c2;
}; cout << "Sum of complex numbers: ";
// Definition of overloaded + operator using friend function [Link]();
Complex operator+(Complex c1, Complex c2) { // Subtracting two complex numbers using overloaded -
Complex temp; // Temporary variable Complex diff = c1 - c2;
[Link] = [Link] + [Link]; cout << "Difference of complex numbers: ";
[Link] = [Link] + [Link]; [Link]();
return temp; return 0; 12
} }
Overloading binary operators - Friend functions
#include <iostream> // Definition of overloaded - operator using friend function
using namespace std; Complex operator-(Complex &c1, Complex &c2) {
class Complex { Complex temp; // Temporary variable
int real, imag; [Link] = [Link] - [Link];
public: [Link] = [Link] - [Link];
// Constructor return temp;
Complex(int r = 0, int i = 0) { }
real = r; imag = i; } int main() {
// Friend function to overload + operator Complex c1(5, 6), c2(2, 3);
friend Complex operator+(Complex &c1, Complex &c2); cout << "First complex number: ";
// Friend function to overload - operator [Link]();
friend Complex operator-(Complex &c1, Complex &c2); cout << "Second complex number: ";
void display() {// Display function [Link]();
cout << real << " + " << imag << "i" << endl; // Adding two complex numbers using overloaded +
} Complex sum = c1 + c2;
}; cout << "Sum of complex numbers: ";
// Definition of overloaded + operator using friend function [Link]();
Complex operator+(Complex &c1, Complex &c2) { // Subtracting two complex numbers using overloaded -
Complex temp; // Temporary variable Complex diff = c1 - c2;
[Link] = [Link] + [Link]; cout << "Difference of complex numbers: ";
[Link] = [Link] + [Link]; [Link]();
return temp; return 0; 13
} }
Overloading << (Output) and >> (Input)
Operators using Friend Functions
Overloading << and >> in C++ is commonly done using friend functions because
these operators work with streams (ostream, istream), where the left operand is
not an object of our class.
• cout << obj;
cin >> obj;
• cout is an object of ostream
• cin is an object of istream
• So, you cannot overload these as member functions of your class (since your class
is not on the left side).
Hence, we use friend functions.

14
#include <iostream> // Overloading >>
using namespace std; istream& operator>>(istream& in, Student& s) {
cout << "Enter Roll No: ";
class Student { in >> [Link];
private: cout << "Enter Name: ";
int rollNo; in >> [Link];
string name; return in;
}
public:
friend ostream& operator<<(ostream& out, const Student& s); int main() {
friend istream& operator>>(istream& in, Student& s); Student s;
};
cin >> s; // calls operator>>
// Overloading << cout << s; // calls operator<<
ostream& operator<<(ostream& out, const Student& s) {
out << "Roll No: " << [Link] << endl; return 0;
out << "Name: " << [Link] << endl; }
return out;
}

15
Overloading << (Output) and >> (Input)
Operators using Friend Functions
#include <iostream>
using namespace std;
class Complex {
int real, imag;
public:
// Constructor
Complex(int r = 0, int i = 0) {
real = r;
imag = i;
}
// Friend function to overload << operator for output
friend ostream & operator <<(ostream &out, Complex c);
// Friend function to overload >> operator for input
friend istream & operator >>(istream &in, Complex &c);
}; 16
Overloading << (Output) and >> (Input)
Operators using Friend Functions
// Overloading << operator for output
ostream & operator <<(ostream &out, Complex c) {
out << [Link] << " + " << [Link] << "i";
return out; // Return the stream to allow chaining (e.g., cout << c1 << c2;)
}

// Overloading >> operator for input


istream & operator >>(istream &in, Complex &c) {
cout << "Enter real part: ";
in >> [Link];
cout << "Enter imaginary part: ";
in >> [Link];
return in; // Return the stream to allow chaining (e.g., cin >> c1 >> c2;)
}
17
Overloading << (Output) and >> (Input)
Operators using Friend Functions
int main() {
Complex c1, c2;

// Taking user input for two complex numbers


cout << "Enter first complex number:" << endl;
cin >> c1;
cout << "Enter second complex number:" << endl;
cin >> c2;

// Displaying complex numbers using overloaded <<


cout << "First Complex Number: " << c1 << endl;
cout << "Second Complex Number: " << c2 << endl;

return 0;
} 18
Dynamic Polymorphism
• the function call in runtime polymorphism is resolved at runtime.
• implemented using function overriding with virtual functions.
• Function Overriding occurs when a derived class defines one or more
member functions of the base class. That base function is said to be
overridden. The base class function must be declared as virtual
function for runtime polymorphism to happen.

19
Function overriding

20
#include <iostream> int main() {
using namespace std; Base* basePtr; // Base class pointer
Base base;
class Base { basePtr=&base;
public: basePtr->show();
void show() { Derived d; // Derived class object
cout << "Base class show() function" << endl; basePtr = &d; // Base class pointer points to derived class object
} basePtr->show();
};
return 0;
class Derived : public Base { }
public:
void show() { // Overriding base class function
cout << "Derived class show() function" << endl;
}
};

21
Virtual Functions
• A virtual function in C++ is a member function in a base class that you can
override in a derived class.
• It allows runtime polymorphism, meaning that the function call is resolved
at runtime rather than compile-time.
• When a base class pointer points to a derived class object, calling a
function without virtual results in compile-time binding (i.e., the base class
function gets called).
• However, with virtual, the function call is resolved at runtime, calling the
derived class function instead.
• If a derived class does not override the virtual function, the base class
version is called.

22
Virtual function

#include <iostream> int main() {


using namespace std; Base* basePtr; // Base class pointer
Base base;
class Base { basePtr=&base;
public: basePtr->show();
virtual void show() { // Virtual function Derived d; // Derived class object
cout << "Base class show() function" << endl; basePtr = &d; // Base class pointer points to derived class object
} basePtr->show();
};
return 0;
class Derived : public Base { }
public:
void show() { // Overriding base class function
cout << "Derived class show() function" << endl;
}
};
23
Virtual function
#include <iostream> int main() {
using namespace std; Base* basePtr; // Base class pointer
Base base;
class Base { basePtr=&base;
public: basePtr->show();
virtual void show() { // Virtual function Derived d; // Derived class object
cout << "Base class show() function" << endl; basePtr = &d; // Base class pointer points to derived class object
} basePtr->show();
};
return 0;
class Derived : public Base { }
public:
/*void show() { // Overriding base class function
cout << "Derived class show() function" << endl;
}*/
};

24
25
Pure Virtual Function
• If a function is marked as = 0, it becomes a pure virtual function,
making the class abstract (cannot be instantiated).
class Base {
public:
virtual void show() = 0; // Pure virtual function
//This forces derived classes to implement show().
};

26
Abstract Class
• A class containing at least one pure virtual function is called an
abstract class, and it cannot be instantiated.
• A pure virtual function serves as a placeholder in the base class. It
forces derived classes to provide their own implementation.
• The derived class must override it; otherwise, it will also become an
abstract class.

27
Pure Virtual function
#include <iostream> // Another derived class
using namespace std; class Rectangle : public Shape {
public:
// Abstract class void draw() {
class Shape { cout << "Drawing Rectangle" << endl;
public: }
// Pure virtual function };
virtual void draw() = 0; int main() {
}; Shape* s; // Pointer to abstract class

// Derived class Circle c;


class Circle : public Shape { Rectangle r;
public: s = &c;
void draw() { s->draw(); // Calls Circle's draw()
cout << "Drawing Circle" << endl; s = &r;
} s->draw(); // Calls Rectangle's draw()
}; return 0;
} 28
Pure Virtual function
#include <iostream> // Final derived class
using namespace std; class Rectangle : public Polygon {
// Abstract class public:
class Shape { void area() {
public: cout << "Area of Rectangle = " << length * breadth << endl;
virtual void area() = 0; // Pure virtual function }
}; };

// Intermediate class (still abstract) int main() {


class Polygon : public Shape { Shape* ptr; // Base class pointer
protected: Rectangle r;
int length, breadth; [Link](10, 5);
public: ptr = &r; // Pointing to derived object
void setValues(int l, int b) { ptr->area(); // Runtime polymorphism
length = l; return 0;
breadth = b; }
}
}; 29
class Rectangle : public Shape {// Derived class
int length, breadth;
Pure Virtual function public:
void setDimensions(int l, int b) {
length = l;
breadth = b;
#include <iostream> }
using namespace std; void area() {
cout << "Area of Rectangle = " << length * breadth << endl;
// Abstract base class }
class Shape { void show() { // Overriding pure virtual function
public: cout << "This is Rectangle class" << endl;
// Pure virtual function (must be overridden) }
virtual void show() = 0; };
int main() {
// Non-virtual function Shape* ptr; // Base class pointer
void display() { Rectangle r;
cout << "Display from Shape class" << endl; [Link](10, 5);
} ptr = &r;
}; ptr->show(); // Runtime polymorphism (pure virtual function)
ptr->display(); // Non-virtual function
[Link](); // Derived class specific function
return 0;
} 30
Virtual Destructor
• A virtual destructor ensures that when you delete an object using a
base class pointer, the destructor of the derived class is also called.
• This is very important in dynamic polymorphism, especially when
working with dynamic memory (new / delete).

31
#include <iostream>
using namespace std;

class Base {
public: Only Base destructor is called
~Base() { Derived destructor is NOT called
cout << "Base Destructor" << endl; This can cause memory leaks if Derived has allocated resources
}
};
class Derived : public Base {
public:
~Derived() {
cout << "Derived Destructor" << endl;
}
};
int main() {
Base* ptr = new Derived();
delete ptr; // Problem here
return 0;
}
32
#include <iostream>
using namespace std;

class Base {
public: Always use virtual destructor when:
virtual ~Base() { You have a base class pointer
cout << "Base Destructor" << endl; You use inheritance
Objects are deleted dynamically
}
Destructor order:
}; Derived → Base
class Derived : public Base {
public:
~Derived() {
cout << "Derived Destructor" << endl;
}
};
int main() {
Base* ptr = new Derived();
delete ptr; // Problem here
return 0;
}
33

You might also like