Operator Overloading & Inheritance
Module – 3
Operator Overloading: Creating a Member Operator Function, Operator Overloading
Using a Friend Function, Overloading new and delete.
Inheritance: Base-Class Access Control, Inheritance and Protected Members,
Inheriting Multiple Base Classes, Constructors, Destructors and Inheritance, Granting
Access, Virtual Base Classes.
Polymorphism:
Polymorphism = “many forms.”
It means the same function name or operator can behave differently based on the
context.
In C++, polymorphism is of two types:
1. Compile-time polymorphism (static binding)
2. Run-time polymorphism (dynamic binding)
Compile-time polymorphism is implemented in C++ using:
1. Function Overloading
2. Operator Overloading
Operator Overloading:
Operator overloading is a feature in C++ that allows programmers to redefine the
behavior of existing operators (such as +, -, *, ==, etc.) for user-defined types
(classes or objects).
Enables objects to use operators (+, -, *, new, delete, etc.) like built-in data types.
Similar to function overloading, but applied to operators.
Allows user-defined objects to behave like primitive types in expressions (e.g., a +
b).
Why We Need Operator Overloading?
Improves code readability and intuitiveness.
Enables natural syntax for operations on complex objects (e.g., vectors, matrices,
strings).
Makes custom classes integrate seamlessly into C++ expressions.
Dept. of ISE, BMSIT&M 1
Operator Overloading & Inheritance
Syntax:
return_type operator symbol (argument_list);
Example:
Complex operator +(Complex c);
Operators That Can Be Overloaded:
Most operators can be overloaded:
+, -, *, /, ==, !=, <, >, ++, --, [], (), ->, <<, >>, =
etc.
Some operators cannot be overloaded:
. (dot), :: (scope resolution), sizeof, typeid, ?:, .*
NOTE:
o Overloading does not change operator precedence or associativity.
o You cannot create new operators, only redefine existing ones.
o Overloaded operators should behave logically and consistently with their
meaning.
o Avoid confusing or unnatural operator use (e.g., don’t overload + to subtract).
Real-Life Examples
Complex Numbers : Overload +, - to add/subtract complex objects.
Vectors/Matrices : Overload * for multiplication.
Strings : Overload + for concatenation.
I/O Streams : << and >> are overloaded in iostream for user-defined types.
Special Operators
Overloading new and delete allows custom memory allocation control.
Overloading assignment (=) ensures deep copy behavior in classes managing
dynamic memory.
Dept. of ISE, BMSIT&M 2
Operator Overloading & Inheritance
Example:
class Add
{
int a;
public:
//Needs a default constructor to create a blank object to hold the result
Add() {} // default constructor
Add(int x) { a = x; } // parameterized constructor
Add operator+(Add obj) // Overload + operator
{
Add temp;
temp.a = a + obj.a; // add values of both objects
return temp;
}
void show()
{
cout << "Value = " << a << endl;
}
};
int main()
{
Add obj1(10), obj2(20), obj3;
obj3 = obj1 + obj2; // uses operator+()
[Link](); // Output: Value = 30
return 0;
}
NOTE: We need the default constructor so that:
We can create temporary objects (like temp) inside operator functions.
We can declare objects without passing arguments (like Add obj3;).
Dept. of ISE, BMSIT&M 3
Operator Overloading & Inheritance
Left operand → implicit
For binary operators (like +, -, =), the left operand is passed automatically using the
this pointer.
The right operand is passed as the argument.
Usually returns an object of the same class, so the result can be
used in further expressions.
Overloading Unary ++ Operator (Prefix):
The dummy int parameter in postfix form is not used, it only helps the compiler
distinguish between prefix and postfix versions.
Both can be overloaded as member functions or friend functions.
Syntax:
Prefix:
Number& operator++()
{
++ value; // increment first
return *this; // return updated object
}
Postfix:
return_type class_name::operator++(int)
{
// dummy int used to differentiate from prefix
// increment or modify after using
}
Dept. of ISE, BMSIT&M 4
Operator Overloading & Inheritance
Example:
class Number
{
int x;
public:
Number(int a) { x = a; }
// Prefix ++
Number& operator++() { // ++obj
++x; // increment first
return *this; // return updated object
}
// Postfix ++
Number operator++(int) { // obj++
Number temp = *this; // store old value
x++; // then increment
return temp; // return old value
}
void show()
{
cout << "x = " << x << endl;
}
};
int main()
{
Number n1(5);
cout << "Original value:\n";
[Link](); // 5
++n1; // prefix: increment first
cout << "After prefix ++:\n";
[Link](); // 6
Dept. of ISE, BMSIT&M 5
Operator Overloading & Inheritance
n1++; // postfix: use old value, then increment
cout << "After postfix ++:\n";
[Link](); // 7
return 0;
}
class Add
{
public:
int a;
Add(int x = 0) { a = x; } // default + parameterized constructor
Add& operator++() // prefix increment
{
++a; // increment value
return *this; // return reference to same object
}
void display()
{
cout << "a = " << a << endl;
}
};
int main()
{
Add obj3(5); // start with a = 5
++obj3; // prefix increment → a becomes 6
[Link](); // Output: a = 6
return 0;
}
Dept. of ISE, BMSIT&M 6
Operator Overloading & Inheritance
Friend Function in Operator Overloading:
Normally, operator overloading is done using member functions.
But sometimes, we need to overload an operator using a non-member (friend)
function.
Friend functions are useful when left operand is not an object of the same class.
A friend function:
o Is not a member of the class.
o Has access to private data of the class.
o Does not have this pointer (since it's not a class member).
o Must be declared inside the class using the friend keyword.
o Friend functions cannot overload the following operators:
=, (), [], or ->
Syntax:
friend ClassName operator op_symbol (ClassName obj1, ClassName obj2);
Example1:
class A;
class B; // forward declaration
class A
{
int x;
public:
A(int a) { x = a; }
friend void operator+(A, B); // declare friend operator function
};
class B
{
int y;
public:
B(int b) { y = b; }
Dept. of ISE, BMSIT&M 7
Operator Overloading & Inheritance
friend void operator+(A, B); // friend of both
};
// define the operator+ friend function
void operator+(A obj1, B obj2)
{
cout << "Sum = " << obj1.x + obj2.y << endl;
}
int main()
{
A a1(10);
B b1(20);
a1 + b1; // calls operator+ function
return 0;
}
Example2:
class sample
{
int a;
public:
sample(){};
sample(int x)
{ a = x; }
friend sample operator +(int value, sample &s2)
{
sample temp;
temp.a = value + s2.a;
return temp;
}
void display()
{
cout<<a;
Dept. of ISE, BMSIT&M 8
Operator Overloading & Inheritance
}
};
int main()
{
sample m(15), n(20), p;
p = 10 + n; // using friend
[Link]();
return 0;
}
Overloading new and delete Operators:
The operators new and delete are used to dynamically allocate and deallocate
memory.
new : allocates memory using the heap and then calls the constructor.
delete : calls the destructor and then frees the memory.
You can overload these operators to customize how memory is managed.
To handle low-memory situations.
To log or trace every allocation/deallocation.
To implement custom memory pools for faster allocation.
To add safety or error checking.
Syntax:
void* operator new(size_t size)
{
// allocate memory of 'size' bytes
// throw bad_alloc if allocation fails
return pointer_to_memory;
}
size_t :
An unsigned integer type that can represent the size
of any object.
Dept. of ISE, BMSIT&M 9
Operator Overloading & Inheritance
void operator delete(void* p)
{
// free memory pointed by p
}
Operator Purpose Notes
Can be overloaded per class or
operator new(size_t) Allocates memory for object
globally
Must correspond to overloaded
operator delete(void*) Frees allocated memory
new
Represents size of object in
size_t Automatically passed to new
bytes
Exception thrown if memory
bad_alloc Must handle in try–catch
allocation fails
When We Need to Overload new and delete operators:
You want to allocate from a special memory pool, shared memory, or a pre-reserved
block instead of the heap.
For objects frequently created/deleted, using your own pool is much faster than the
system heap.
You can print messages, record which objects were allocated, detect leaks, or log
memory usage.
Instead of crashing on bad_alloc, your custom version can automatically free or swap
memory.
Example:
#include <iostream>
#include <cstdlib> // for malloc() and free()
using namespace std;
class Sample
{
int x;
public:
Sample(int a)
{
Dept. of ISE, BMSIT&M 10
Operator Overloading & Inheritance
x = a;
}
void show()
{
cout << "Value = " << x << endl;
}
// Overload new
void* operator new(size_t size)
{
cout << "Custom new called! Size = "
<< size << " bytes" << endl;
void* p = malloc(size); // allocate memory
return p;
}
// Overload delete
void operator delete(void* p)
{
cout << "Custom delete called!" << endl;
free(p); // free memory
}
};
int main()
{
// create object using overloaded new
Sample *obj = new Sample(10);
obj->show();
// delete object using overloaded delete
delete obj;
return 0;
}
Dept. of ISE, BMSIT&M 11
Operator Overloading & Inheritance
Aspect Normal new / delete Overloaded new / delete
Built-in operators in C++ for User-defined versions of new and
Definition dynamic memory allocation and delete that can customize how
deallocation. memory is allocated and freed.
Defined by programmer inside a class
Who provides it Provided by C++ runtime system.
or globally.
Allocates memory from the heap and Used when you want special memory
Purpose calls the constructor/destructor management, logging, pooling, or
automatically. debugging.
void* operator new(size_t
ptr = new ClassName;delete
Syntax size)void operator delete(void*
ptr;
p)
Can allocate from custom source
Memory source Uses default heap memory.
(pool, shared memory, file, etc.).
Throws bad_alloc automatically on Programmer must handle errors
Error handling
failure. (usually by throwing bad_alloc).
Still called automatically —
Destructor call Automatically called after delete. overloading doesn’t change this
behavior.
Can be class-specific or global
Scope Global (for all types).
depending on where defined.
Can display messages like "Custom
Example Output (No message shown) new called!" / "Custom delete
called!"
Advanced cases like tracking
Simple, general-purpose memory
Use case memory, object pooling,
allocation.
performance tuning.
Dept. of ISE, BMSIT&M 12
Operator Overloading & Inheritance
Inheritance:
Inheritance is one of the core features of Object-Oriented Programming (OOP).
It allows one class to acquire the properties (data members) and behaviors
(member functions) of another class.
Base Class (Parent Class) : The class whose features are inherited.
Derived Class (Child Class) : The class that inherits from the base class.
Real-time examples:
1. In a university database, all types of people (students, faculty, staff) share some basic
information, but each has specialized data and behavior.
The base class Person contains common attributes such as name, age,
and address.
The derived classes add their own specific features:
o Student roll number, course, marks
o Faculty employee ID, department, subject taught
o Staff job title, shift timings.
Dept. of ISE, BMSIT&M 13
Operator Overloading & Inheritance
2. A bank software system can use inheritance to manage all types of accounts
efficiently, common operations are handled in the base class, while special cases are
handled by derived classes.
The base class Account defines common features such as:
accountNumber, balance, deposit (), and withdraw ().
Each derived class modifies or adds unique features:
o SavingsAccount interest rate, calculateInterest()
o CurrentAccount overdraft limit, checkOverdraft()
o LoanAccount loan amount, calculateEMI()
Base-Class Access Control:
When a class inherits another, the members of the base class become members of the
derived class.
Syntax:
class derived-class-name : access base-class-name
{
// body of class
};
Here,
The access status of the base-class members inside
the derived class is determined by access.
The access specifier (public, protected, or
private) after the colon determines how members of
the base class are inherited by the derived class.
Public Inheritance:
Syntax:
class Derived : public Base { ... };
Public members of Base stay public in Derived.
Protected members of Base stay protected in Derived.
Private members of Base not accessible in Derived.
Dept. of ISE, BMSIT&M 14
Operator Overloading & Inheritance
Private Inheritance:
Syntax:
class Derived : private Base { ... };
Public and Protected members of Base become private in Derived.
Private members of Base remain inaccessible.
Protected Inheritance:
Syntax:
class Derived : protected Base;
Both public and protected members of the base become protected in the derived
class.
Private members of Base remain inaccessible.
Base-Class Member Accessibility in Derived Classes:
Base Member Type Public Inheritance Protected Inheritance Private Inheritance
Public Public Protected Private
Protected Protected Protected Private
Private Not Inherited Not Inherited Not Inherited
Example1:
class base // Base class definition
{
int i, j; // private data members (accessible only through public functions)
public:
void set(int a, int b)
{
i = a;
j = b;
}
void show()
{
cout << "Values in base class: "
<< i << " " << j << endl;
}
};
Dept. of ISE, BMSIT&M 15
Operator Overloading & Inheritance
// Derived class using public inheritance
class derived : public base
{
int k; // additional member in derived class
public:
derived(int x)
{
k = x;
}
void showk()
{
cout << "Value in derived class: "
<< k << endl;
}
};
// Main function
int main()
{
derived ob(3); // create object of derived class
[Link](1, 2); // access base class public member
[Link](); // access base class public member
[Link](); // access derived class member
return 0;
}
Example1:
class base
{
int i, j;
public:
void set(int a, int b) { i = a; j = b; }
void show() { cout << i << " " << j << "\n"; }
};
Dept. of ISE, BMSIT&M 16
Operator Overloading & Inheritance
// Public elements of base are private in derived
class derived : private base {
int k;
public:
derived(int x) { k = x; }
void showk() { cout << k << "\n"; }
};
int main()
{
derived ob(3);
[Link](1, 2); // ERROR: 'set' is private in 'derived'
[Link](); // ERROR: 'show' is private in 'derived'
return 0;
}
Types of Inheritance in C++
Type Description Example
One base class → one derived
1. Single Inheritance Student ← Person
class
One derived class inherits from TeachingAssistant ←
2. Multiple Inheritance
two or more base classes Student, Faculty
A derived class acts as a base class Grandfather → Father
3. Multilevel Inheritance
for another class (chain-like) → Son
Multiple derived classes inherit Student, Teacher ←
4. Hierarchical Inheritance
from the same base class Person
5. Hybrid (or Virtual) Combination of two or more types Mix of multiple +
Inheritance (used to solve diamond problem) multilevel
Dept. of ISE, BMSIT&M 17
Operator Overloading & Inheritance
Inheritance and protected Members:
The protected keyword gives more flexibility in inheritance than private.
A protected member is not accessible by non-member functions or outside the class,
except for inheritance, a protected member behaves the same as a private member.
Private members of a base class are not accessible by derived classes, Protected
members, when inherited, can be accessed by derived classes.
If a base class is inherited publicly, its protected members remain protected in the
derived class, Protected allows data to be hidden from the outside world, yet usable
within derived classes.
It is useful when you want controlled access to class members during inheritance.
It is possible to inherit a base class as protected. When this is done, all public and
protected members of the base class become protected members of the derived class.
Example:
class base
{
protected:
int i, j; // private to base, but accessible by derived
public:
void set(int a, int b)
{
i = a;
j = b;
}
void show()
{
cout << i << " " << j << "\n";
}
};
class derived : public base
{
int k;
public:
// derived may access base's i and j
void setk()
{ k = i * j; } // accessing protected members from base
Dept. of ISE, BMSIT&M 18
Operator Overloading & Inheritance
void showk()
{
cout << k << "\n";
}
};
int main()
{
derived ob;
[Link](2, 3); // OK: public function of base
[Link](); // OK: public function of base
[Link](); // OK: derived accessing protected members
[Link](); // OK: display result
return 0;
}
Inheriting Multiple Base Classes
It is possible for a derived class to inherit two or more base classes. For example,
in this short example, derived inherits both base1 and base2.
Example:
class base1
{
protected:
int x;
public:
void showx() {
cout << x << "\n";
}
};
class base2
{
protected:
int y;
public:
void showy() {
cout << y << "\n";
}
};
Dept. of ISE, BMSIT&M 19
Operator Overloading & Inheritance
// Inherit from multiple base classes
class derived : public base1, public base2
{
public:
void set(int i, int j) {
x = i;
y = j;
}
};
int main() {
derived ob;
[Link](10, 20); // provided by derived
[Link](); // from base1
[Link](); // from base2
return 0;
}
Constructors, Destructors, and Inheritance
There are two major questions that arise relative to constructors and destructors when
inheritance is involved.
o First, when are base-class and derived-class constructor and destructor
functions called?
o Second, how can parameters be passed to base-class constructor functions?
When Constructor and Destructor functions called??
It is possible for a base class, a derived class, or both to contain constructor and/or
destructor functions.
It is important to understand the order in which these functions are executed when
an object of a derived class comes into existence and when it goes out of existence.
Constructor of the base class executes first, followed by the derived class
constructor.
Destructors execute in reverse order, the derived class destructor runs first, then the
base class destructor.
This ensures that the base part of the object is initialized before the derived part.
Similarly, during destruction, the derived part is destroyed before the base part.
Dept. of ISE, BMSIT&M 20
Operator Overloading & Inheritance
If multiple base classes exist, their constructors execute in the order of inheritance
declaration.
Destructors execute in the reverse order of construction.
Both base and derived classes can have their own constructors and destructors.
Constructors and destructors are automatically called when an object is created and
destroyed.
Example:
class base {
public:
base()
{
cout << "Constructing base\n";
}
~base()
{
cout << "Destructing base\n";
}
};
class derived : public base {
public:
derived()
{
cout << "Constructing derived\n";
}
~derived()
{
cout << "Destructing derived\n";
}
};
int main()
{
derived ob;
// do nothing but construct and destruct ob
return 0;
}
Dept. of ISE, BMSIT&M 21
Operator Overloading & Inheritance
Passing Parameters to Base-Class Constructors:
When a base class has a parameterized constructor, the derived class must pass
arguments to it.
This is done using a constructor initializer list in the derived class.
Syntax:
derived-constructor(arg-list) : base1(arg-list),
base2(arg-list),
// ... baseN(arg-list)
{
// body of derived constructor
}
The base class constructor executes first, then the derived class constructor.
Used when both base and derived classes need different initialization parameters.
Supports multiple base classes each base can be initialized in the list.
Ensures proper object initialization before the derived class logic runs.
Example1:
class base
{
protected:
int i;
public:
base(int x)
{
i = x;
cout << "Constructing base\n";
}
~base() {
cout << "Destructing base\n";
}
};
class derived : public base
{
int j;
public:
Dept. of ISE, BMSIT&M 22
Operator Overloading & Inheritance
// derived uses x; y is passed along to base.
derived(int x, int y) : base(y)
{
j = x;
cout << "Constructing derived\n";
}
~derived() {
cout << "Destructing derived\n";
}
void show() {
cout << i << " " << j << "\n";
}
};
int main()
{
derived ob(3, 4);
[Link](); // displays 4 3
return 0;
}
Example2:
// First base class
class A {
protected:
int a;
public:
A(int x)
{
a = x;
cout << "Constructing A with value "
<< a << endl;
}
~A() {
cout << "Destructing A\n";
}
};
Dept. of ISE, BMSIT&M 23
Operator Overloading & Inheritance
class B { // Second base class
protected:
int b;
public:
B(int y) {
b = y;
cout << "Constructing B with value "
<< b << endl;
}
~B() {
cout << "Destructing B\n";
}
};
// Derived class inherits from both A and B
class C : public A, public B {
int c;
public:
// Pass arguments to both base classes
C(int x, int y, int z) : A(x), B(y)
{
c = z;
cout << "Constructing C with value "
<< c << endl;
}
~C() {
cout << "Destructing C\n";
}
void show() {
cout << "Values: " << a << " "
<< b << " " << c << endl;
}
};
int main()
{
C obj(10, 20, 30);
[Link]();
return 0;
}
Dept. of ISE, BMSIT&M 24
Operator Overloading & Inheritance
Granting Access:
When a base class is inherited as private, all its public and protected members
become private in the derived class.
Sometimes, we may want to make some of those members public again in the derived
class. This process is called “granting access” or “restoring access specification.”
There are two ways to restore access:
1. Using using statement Preferred modern approach
using base::member;
2. Access declaration (old method, now deprecated)
base::member;
Example:
class base
{
public:
int j; // public in base
};
class derived: private base // Inherit base as private.
{
public:
// here is access declaration
base::j; // make j public again
.
.
.
};
Dept. of ISE, BMSIT&M 25
Operator Overloading & Inheritance
Virtual Base Classes
When a class inherits from two classes that both inherited the same base class, the
base class gets duplicated.
Virtual inheritance removes duplicate base class copies
In derived3, there will be:
one base from derived1, one base from derived2
That means two copies of i exist.
ob.i = 10;
becomes ambiguous: Which i? The one from derived1 or derived2?
Use Scope Resolution Manually
You can tell C++ exactly which version of i to use:
ob.derived1::i = 10;
Making Base a Virtual Base Class
When inheriting from base, use:
class derived1 : virtual public base
class derived2 : virtual public base
Now both classes share the same single base object, instead of creating two copies.
With virtual inheritance:
o derived3 contains only one base.
ob.i = 10; // NOT ambiguous
[Link] = ob.i + ob.j + ob.k;
Dept. of ISE, BMSIT&M 26
Operator Overloading & Inheritance
Example:
class base {
public:
int i;
};
class derived1 : virtual public base {
public:
int j;
};
class derived2 : virtual public base {
public:
int k;
};
/* derived3 inherits both derived1 and derived2.
This time, there is only one copy of base class. */
class derived3 : public derived1, public derived2 {
public:
int sum;
};
int main()
{
derived3 ob;
ob.i = 10; // now unambiguous (only ONE base class exists)
ob.j = 20;
ob.k = 30;
[Link] = ob.i + ob.j + ob.k;
cout << ob.i << " ";
cout << ob.j << " " << ob.k << " ";
cout << [Link];
return 0;
}
Dept. of ISE, BMSIT&M 27