Oops Module3
Oops Module3
C++(BCS306B)
Module – 3
Chapter 1 :
OPERATOR OVERLOADING :
SYLLABUS:
Operator Overloading: Creating a Member Operator Function, Operator Overloading Using a Friend Function,
By,
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.
Dr. Madhu B.G.
Associate Professor, Department of CS&E
AIT, Chikkamagaluru - 577102
Website:vtucode.i
Email
n : [email protected]
[email protected]
Mobile: 9611699567
C++ Operator Overloading :
int a; float
b,sum; sum = a +
b;
● Here, variables “a” and “b” are of types “int” and “float”, which are built-in
data types. Hence the addition operator ‘+’ can easily add the contents of
“a” and “b”.
int main()
{
A a1, a2, a3;
a3 = a1 + a2;
return 0;
}
● In this example, we have 3 variables “a1”, “a2” and “a3” of type “class A”. Here
we are trying to add two objects “a1” and “a2”, which are of user-defined type
i.e. of type “class A” using the “+” operator.
● This is not allowed, because the addition operator “+” is predefined to
operate only on built-in data types.
● But here, “class A” is a user-defined type, so the compiler generates an error.
This is where the concept of “Operator overloading” comes in.
● Now, if the user wants to make the operator “+” add two class objects, the
user has to redefine the meaning of the “+” operator such that it adds two
class objects.
● This is done by using the concept of “Operator overloading”. So the main
idea behind “Operator overloading” is to use C++ operators with class
variables or class objects.
● Redefining the meaning of operators really does not change their original
meaning; instead, they have been given additional meaning along with their
existing ones.
3.1 Creating a Member Operator Function
● Operator overloading is the process of making an operator exhibit different
behaviors in different instances.
Ways of operator overloading
1) Operator overloading of member functions.
2) Operator overloading of non-member or friend functions.
Here,
returnType is the return type of the function.
the operator is a keyword.
the symbol is the operator that we want to overload. Like: +, <, -, ++, etc.
arguments are the arguments passed to the function.
Complete Example to add two Complex Numbers in C++:
#include<iostream>
using namespace std;
class Complex
{
private:
int real;
int img;
public:
Complex (int r = 0, int i = 0)
{
real = r; img
= i;
}
Complex add (Complex x)
{
Complex temp;
temp.real = real + x.real; temp.img
= img + x.img; return temp;
}
void Display() {
cout << real << "+i" << img <<endl;
}
};
int main()
{
Complex C1 (3, 7);
C1.Display(); Complex
C2 (5, 2); C2.Display();
Complex C3;
C3 = C1.add (C2);
C3.Display(); // C2.add(C1);
}
OUTPUT :
Example to add two Complex Numbers in C++ using Operator Overloading:
#include<iostream>
using namespace
std; class Complex
{
private:
int real;
int img;
public:
Complex (int r = 0, int i = 0)
{
real = r; img
= i;
}
Complex operator * (Complex x)
{
Complex temp;
temp.real = real * x.real; temp.img =
img * x.img; return temp;
}
void Display() {
cout << real << "+i" << img <<endl;
}
};
● Then only their friend can add the money. So, the same approach will
follow for the friend function.
#include <iostream> using
namespace std; class
Complex
{
private:
int real;
int img;
public:
Complex (int r = 0, int i = 0)
{
real = r;
img = i;
}
void Display ()
{
cout << real << "+i" << img;
}
friend Complex operator + (Complex c1, Complex c2);
};
Complex operator + (Complex c1, Complex c2)
{
Complex temp;
temp.real = c1.real + c2.real; temp.img =
c1.img + c2.img; return temp;
}
int main ()
{
Complex C1(5, 3), C2(10, 5), C3;
C1.Display(); cout
<< " + ";
C2.Display(); cout
<< " = "; C3 = C1 +
C2;
C3.Display();
}
OUTPUT:
5+i3 + 10+i5 = 15+i8
3.3 Overloading new and delete
The new operator allocates memory to a variable. For example,
// declare an int pointer int*
pointVar;
// dynamically allocate memory using the new keyword
pointVar = new int;
// assign value to allocated memory
*pointVar = 45;
Here, we have dynamically allocated memory for an int variable using the
new operator.
Notice that we have used the pointer pointVar to allocate the memory dynamically
This is because the new operator returns the address of the memory location.
In the case of an array, the new operator returns the address of the first element of
the array.
From the example above, we can see that the syntax for using the new operator is
pointerVariable = new dataType;
delete Operator
Once we no longer need to use a variable that we have declared dynamically,
we
can deallocate the memory occupied by the variable.
For this, the delete operator is used. It returns the memory to the operating
system. This is known as memory deallocation.
delete pointerVariable;
The general form of operator overloading new
The general form of overloading the new operator is as follows:
here
● return_type is a type (class) to which the operator function returns a pointer
for
which memory is allocated by a special (non-standard method);
● size – size of memory that is allocated for return_type type.
(size_t is essentially an unsigned integer.) The parameter size will contain the
number of bytes needed to hold the object being allocated.
The general form of operator overload delete
The general form of operator overload delete is as follows:
void operator delete(void * pointer)
{
// freeing the memory pointed to by the pointer pointer
// ...
}
here pointer – a pointer to the memory area that was previously allocated by
the operator new.
Why overload new and delete?
● You might choose to do this if you want to use some special allocation
method.
● For example, you may want allocation routines that automatically begin using
a disk file as virtual memory when the heap has been exhausted.
● The new and delete operators can also be overloaded like other operators in
C++. New and Delete operators can be overloaded globally or they can be
overloaded for specific classes.
● If these operators are overloaded using member function for a class, it
means that these operators are overloaded only for that specific class.
● If overloading is done outside a class (i.e. it is not a member function of a
class), the overloaded ‘new’ and ‘delete’ will be called anytime you make use
of these operators (within classes or outside classes). This is global
overloading.
#include <iostream> using
namespace std;
class MyClass
{
int num;
public:
MyClass()
{
}
MyClass(int a)
{
num = a ;
}
void display()
{
cout<< "num:" << num << endl;
}
void *operator new(size_t size)
{
cout<< "Overloading new operator with size: " << size
<< endl;
void * p = malloc(size) ;
return p;
}
void operator delete(void * p)
{
cout<< "Overloading delete operator " << endl; free(p);
}
};
int main()
{
MyClass *p = new MyClass(24);
p->display();
delete p;
}
OUTPUT:
INHERITANCE:
3.4 Base-Class Access
Control
When a class inherits another, the members of the base class become
members of the derived class. Class inheritance uses this general form:
● The access status of the base-class members inside the derived class is
determined by access. The base-class access specifier must be either
public, private, or protected.
● If no access specifier is present, the access specifier is private by default if
the derived class is a class. If the derived class is a struct, then public is the
default in the absence of an explicit access specifier.
● When the access specifier for a base class is public, all public members
of the base become public members of the derived class, and all
protected members of the base become protected members of the
derived class.
● In all cases, the base's private elements remain private to the base and
are
not accessible by members of the derived class.
In C++ inheritance, we can derive a child class from the base class in
different
access modes. For example,
class Base
{
.... ... ....
};
int main()
{
PublicDerived object1; cout <<
"Private = " << cout << "Protected = object1.getPVT() << endl;
" << object1.getProt() << endl;
cout << "Public = " << object1.pub << endl;
return 0;
}
Output :
Private = 1
Protected = 2
Public = 3
Here, we have derived PublicDerived from Base in public mode.
As a result, in PublicDerived:
{
// code of the derived class
}
In the above syntax, class A and class B are two base classes, and class C is
the
child class that inherits some features of the parent classes.
Example 1: Program to use the Multiple Inheritance
Output :
It is the first function of the Base class It is the second
function of the Base class It is the function of the derived
class
3.7 Constructors
Constructor in C++ is a special method that is invoked automatically at the
time of object creation. It is used to initialize the data members of new
objects generally. The constructor in C++ has the same name as the class or
structure.
To create a constructor,
use the same name as the class, followed by parentheses ():
class MyClass { // The class
public: // Access specifier
MyClass() { // Constructor
cout << "Hello World!";
}
};
int main() {
MyClass myObj; // Create an object of MyClass (this will call the
constructor)
return 0;
}
Output:
Hello World
// Example: defining the constructor within the class
#include<iostream> using
namespace std; class
student
{
int rno;
char name[50];
double fee; public:
student()
{
int main()
{
student s; //constructor gets called automatically
when we create the object of the class
s.display();
return 0;
OutPut:
Enter the RollNo:Enter the Name:Enter the Fee: 2 0
Example: defining the constructor outside the class
#include<iostream>
using namespace std; class student
{
int rno;
char name[50]; double fee;
public:
student();
void display();
};
student::student()
{
cout<<"Enter the RollNo:";
cin>>rno;
cout<<"Enter the Name:";
cin>>name; cout<<"Enter the Fee:"; cin>>fee;
}
void student::display()
{
cout<<endl<<rno<<"\t"<<name<<"\t"<<fee;
}
int main()
{
student s;
s.display();
return 0;
}
Output:
class base {
protected:int i;
public:
base(int x) { i=x; cout << "Constructing base\n"; }
~base() { cout << "Destructing base\n"; }
};
~derived()
int main() {
derived ob(3, 4);
ob.show();
return 0;
}
3.8 Destructors and Inheritance
● The destructor of derived class will be called first then destructor of base
class which is mentioned in the derived class declaration is called from last
towards first sequence wise.
● When we are using the constructors and destructors in the inheritance,
parent class constructors and destructors are accessible to the child class
hence when we create an object for the child class, constructors and
destructors of both parent and child class get executed.
#include <iostream> using
namespace std;
~parent() //destructor
{
cout << "Parent class Destructor\n";
}
};
class child : public parent //child class
{
public:
child() //constructor
{
cout << "Child class Constructor\n";
}
~ child() //destructor
{
cout << "Child class Destructor\n";
}
};
int main()
{
//automatically executes both child and parent class
//constructors and destructors because of inheritance
child c;
return 0;
}
Output :
base-class::member;
class base {
public: // public in base
int j;
};
class derived: private base // Inherit base as private.
{
public: // here is access declaration
base::j; // make j public again // ...
};
Because base is inherited as private by derived, the public variable j is made
a
private variable of derived.
● Because base is inherited as private by derived, the public member j is
made a private member of derived. However, by including
base::j;
as the access declaration under derived's public heading, j is restored to
its public status.
● You can use an access declaration to restore the access rights of public
and protected members. However, you cannot use an access declaration
to raise or lower a member's access status.
class base {
int i;
public: int j, k;
void seti(int x) { i = x; }
int geti() { return i; }
};
● To solve this ambiguity we will make class “A” as a virtual base class. To make
a virtual base class “virtual” keyword is used.
● When one class is made virtual then only one copy of its data member and
member function is passed to the classes inheriting it.
● So in our example when we will make class “A” a virtual class then only one
copy of the data member and member function will be passed to the
classes “B” and “C” which will be shared between all classes. This will help
to solve the ambiguity.
using namespace std;
class base {
public:
int a;
A(){
a = 10;
}
};
class B: virtual public A {};
class C: virtual public A {};
class D: public B, public C {};
int main()
{
//creating class D object
D object;
cout << "a = " << object.a << endl;
return 0;
}
Output :
a = 10
#include <iostream>
using namespace std;
class base {
public: int i;
};
int main()
{
derived3 ob;
ob.i = 10; // now unambiguous
ob.j = 20;
ob.k = 30;
// unambiguous
ob.sum = ob.i + ob.j + ob.k;
// unambiguous
cout << ob.i << " ";
cout << ob.j << " " << ob.k << " "; cout << ob.sum;
return 0;
}