0% found this document useful (0 votes)
74 views

Classes & Objects in C++

Uploaded by

spdgupta0
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
74 views

Classes & Objects in C++

Uploaded by

spdgupta0
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 26

C++ Classes and Objects

Class: A class in C++ is the building block, that leads to Object-Oriented programming. It is a user-
defined data type, which holds its own data members and member functions, which can be accessed and
used by creating an instance of that class. A C++ class is like a blueprint for an object.

For Example: Consider the Class of Cars. There may be many cars with different names and brand but
all of them will share some common properties like all of them will have 4 wheels, Speed Limit, Mileage
range etc. So here, Car is the class and wheels, speed limits, mileage are their properties.
• A Class is a user defined data-type which has data members and member functions.
• Data members are the data variables and member functions are the functions used to
manipulate these variables and together these data members and member functions defines
the properties and behaviour of the objects in a Class.
• In the above example of class Car, the data member will be speed limit, mileage etc and
member functions can be apply brakes, increase speed etc.

An Object is an instance of a Class. When a class is defined, no memory is allocated but when it is
instantiated (i.e. an object is created) memory is allocated.

Defining Class and Declaring Objects


A class is defined in C++ using keyword class followed by the name of class. The body of class is
defined inside the curly brackets and terminated by a semicolon at the end.

Declaring Objects: When a class is defined, only the specification for the object is defined; no memory
or storage is allocated. To use the data and access functions defined in the class, you need to create
objects.

Syntax:
ClassName ObjectName;

Accessing data members and member functions: The data members and member functions
of class can be accessed using the dot(‘.’) operator with the object. For example if the name of
object is obj and you want to access the member function with the name printName() then you
will have to write obj.printName().

Accessing Data Members


The public data members are also accessed in the same way given however the private data members
are not allowed to be accessed directly by the object. Accessing a data member depends solely on the
access control of that data member.
This access control is given by Access modifiers in C++. There are three access modifiers: public,
private and protected.
// C++ program to demonstrate accessing of data members
#include <bits/stdc++.h>
using namespace std;
class Test
{
// Access specifier
public:

// Data Members
string testname;

// Member Functions()
void printname()
{
cout << "Testname is: " << testname;
}
};

int main() {

// Declare an object of class geeks


Test obj1;

// accessing data member


obj1.testname = "Abhi";

// accessing member function


obj1.printname();
return 0;
}
Output:
Testname is: Abhi

Access Modifiers in C++:


Access modifiers are used to implement an important aspect of Object-Oriented Programming known
as Data Hiding. Consider a real-life example:
The Research and analysis wing (R&AW), having 10 core members has come in possession of sensitive
confidential information regarding national security. Now we can corelate these core members to data
members or member functions of a class which in turn can be corelated to the R&A wing. These 10
members can directly access confidential information from their wing (the class), but anyone apart from
these 10 members can’t access this information directly i.e. outside functions other than those prevalent
in the class itself can’t access information that is not entitled to them, without having either assigned
privileges (such as those possessed by friend class and inherited class as will be seen in this article
ahead) or access to one of these 10 members who is allowed direct access to the confidential information
(similar to how private members of a class can be accessed in the outside world through public member
functions of the class that have direct access to private members). This is what data hiding is in practice.

Access Modifiers or Access Specifiers in a class are used to assign the accessibility to the class
members. That is, it sets some restrictions on the class members not to get directly accessed by the
outside functions.

There are 3 types of access modifiers available in C++:


1. Public
2. Private
3. Protected
Note: If we do not specify any access modifiers for the members inside the class then by default the
access modifier for the members will be Private.

Let us now look at each one these access modifiers in details:


1. Public: All the class members declared under the public specifier will be available to everyone.
The data members and member functions declared as public can be accessed by other classes and
functions too. The public members of a class can be accessed from anywhere in the program using the
direct member access operator (.) with the object of that class.

Example:
// C++ program to demonstrate public access modifier
#include<iostream>
using namespace std;

class Circle
{
public:
double radius;

double compute_area()
{
return 3.14*radius*radius;
}
};

int main()
{
Circle obj;
obj.radius = 5.5;
cout << "Radius is: " << obj.radius << "\n";
cout << "Area is: " << obj.compute_area();
return 0;
}
Output:
Radius is: 5.5
Area is: 94.985
In the above program the data member radius is declared as public so it could be accessed outside the
class and thus was allowed access from inside main().

2. Private: The class members declared as private can be accessed only by the member functions
inside the class. They are not allowed to be accessed directly by any object or function outside the class.
Only the member functions or the friend functions are allowed to access the private data members of a
class.

Example:
// C++ program to demonstrate private access modifier
#include<iostream>
using namespace std;
class Circle
{
private:
double radius;
public:
double compute_area()
{ // member function can access private data member radius
return 3.14*radius*radius;
}

};
int main()
{
Circle obj;
obj.radius = 1.5; // Error
cout << "Area is:" << obj.compute_area();
return 0;
}
Output:
In function 'int main()':
11:16: error: 'double Circle::radius' is private
double radius;
^
31:9: error: within this context
obj.radius = 1.5;
^
The output of above program is a compile time error because we are not allowed to access the private
data members of a class directly outside the class. Yet an access to obj.radius is attempted, radius being
a private data member we obtain a compilation error.

However, we can access the private data members of a class indirectly using the public member
functions of the class.
Example:
// C++ program to demonstrate private access modifier
#include<iostream>
using namespace std;
class Circle
{
private:
double radius;

public:
void compute_area(double r)
{ // member function can access private data member radius
radius = r;
double area = 3.14*radius*radius;
cout << "Radius is: " << radius << endl;
cout << "Area is: " << area;
}
};

int main()
{
Circle obj;
// trying to access private data member directly outside the class
obj.compute_area(1.5);
return 0;
}
Output:
Radius is: 1.5
Area is: 7.065

3. Protected: Protected access modifier is similar to private access modifier in the sense that it can’t
be accessed outside of it’s class unless with the help of friend class, the difference is that the class
members declared as Protected can be accessed by any subclass(derived class) of that class as well.

Note: This access through inheritance can alter the access modifier of the elements of base class in
derived class depending on the modes of Inheritance.
Example:
// C++ program to demonstrate protected access modifier
#include <bits/stdc++.h>
using namespace std;
class Parent
{
protected:
int id_protected;

};

class Child : public Parent


{
public:
void setId(int id)
{
// Child class is able to access the inherited
// protected data members of base class
id_protected = id;
}

void displayId()
{
cout << "id_protected is: " << id_protected << endl;
}
};

int main() {
Child obj1;
// member function of the derived class can
// access the protected data members of the base class
obj1.setId(81);
obj1.displayId();
return 0;
}
Output:
id_protected is: 81

Member Functions in Classes


The member functions have some special characteristics that are often used in the program development.
These characteristics are:
• Several different classes can use the same function name. The ‘membership label’ will resolve
their scope.
• Member functions can access the private data of the class. A non-member function cannot do
so. (However, an exception to this rule is a friend function discussed later.)
• A member function can call another member function directly, without using the dot operator.

There are 2 ways to define a member function:


• Inside class definition – by default inline function
• Outside class definition – by default non-inline function but can make it inline.
To define a member function outside the class definition we have to use the scope resolution :: operator
along with class name and function name.
//C++ program to demonstrate function declaration outside class
#include <bits/stdc++.h>
using namespace std;
class MFOC
{
public:
string name;
int id;
void printname();
void printid()
{
cout << "Id is: " << id;
}
};

void MFOC::printname()
{
cout << "Name is: " << name;
}

int main() {

MFOC obj1;
obj1.name = "xyz";
obj1.id=15;

obj1.printname();
cout << endl;
obj1.printid();
return 0;
}
Output:
Name is: xyz
Id is: 15

Note that all the member functions defined inside the class definition are by default inline, but you can
also make any non-class function inline by using keyword inline with them. Inline functions are actual
functions, which are copied everywhere during compilation, like pre-processor macro, so the overhead
of function calling is reduced.
Note: Declaring a friend function is a way to give private access to a non-member function.

Nesting of member function:


Private member functions:
Memory allocation for object:
Static members in C++:
In C++, static is a keyword or modifier that belongs to the type not instance. So, instance is not required
to access the static members. In C++, static can be field, method etc.

Advantage of C++ static keyword


Memory efficient: Now we don't need to create instance for accessing the static members, so it saves
memory. Moreover, it belongs to the type, so it will not get memory each time when instance is
created.

C++ Static Data Members:


A field which is declared as static is called static field. Unlike instance field which gets memory each
time whenever you create object, there is only one copy of static field created in the memory. It is shared
to all the objects.
It is used to refer the common property of all objects such as rateOfInterest in case of Account,
companyName in case of Employee etc.

C++ static field example


#include <iostream>
using namespace std;
class Account {
public:
int accno;
string name;
static float rateOfInterest;
Account(int accno, string name)
{
this->accno = accno;
this->name = name;
}
void display()
{
cout<<accno<< "<<name<< " "<<rateOfInterest<<endl;
}
};
float Account::rateOfInterest=6.5;

int main(void) {
Account a1 =Account(201, "Sanjay");
Account a2=Account(202, "Nakul");
a1.display();
a2.display();
return 0;
}
Output:
201 Sanjay 6.5
202 Nakul 6.5

C++ static field example: Counting Objects:


#include <iostream>
using namespace std;
class Account {
public:
int accno;
string name;
static int count;
Account(int accno, string name)
{
this->accno = accno;
this->name = name;
count++;
}
void display()
{
cout<<accno<<" "<<name<<endl;
}
};
int Account::count=0;
int main(void) {
Account a1 =Account(201, "Sanjay");
Account a2=Account(202, "Nakul");
Account a3=Account(203, "Ranjana");
a1.display();
a2.display();
a3.display();
cout<<"Total Objects are: "<<Account::count;
return 0;
}
Output:
201 Sanjay
202 Nakul
203 Ranjana
Total Objects are: 3

Predict the output of following C++ program:


#include <iostream>
using namespace std;

class A
{
public:
A() { cout << "A's Constructor Called " << endl; }
};

class B
{
static A a;
public:
B() { cout << "B's Constructor Called " << endl; }
};

int main()
{
B b;
return 0;
}
Output:
B's Constructor Called
The above program calls only B’s constructor, it doesn’t call A’s constructor. The reason for this is
simple, static members are only declared in class declaration, not defined. They must be explicitly
defined outside the class using scope resolution operator.

If we try to access static member ‘a’ without explicit definition of it, we will get compilation error. For
example, following program fails in compilation.
#include <iostream>
using namespace std;

class A
{
int x;
public:
A() { cout << "A's constructor called " << endl; }
};

class B
{
static A a;
public:
B() { cout << "B's constructor called " << endl; }
static A getA() { return a; }
};

int main()
{
B b;
A a = b.getA();
return 0;
}
Output:
Compiler Error: undefined reference to `B::a'
If we add definition of a, the program will works fine and will call A’s constructor. See the following
program.

#include <iostream>
using namespace std;

class A
{
int x;
public:
A() { cout << "A's constructor called " << endl; }
};

class B
{
static A a;
public:
B() { cout << "B's constructor called " << endl; }
static A getA() { return a; }
};

A B::a; // definition of a

int main()
{
B b1, b2, b3;
A a = b1.getA();
return 0;
}

Output:
A's constructor called
B's constructor called
B's constructor called
B's constructor called
Note that the above program calls B’s constructor 3 times for 3 objects (b1, b2 and b3), but calls A’s
constructor only once. The reason is, static members are shared among all objects. That is why they are
also known as class members or class fields. Also, static members can be accessed without any object,
see the below program where static member ‘a’ is accessed without any object.
#include <iostream>
using namespace std;

class A
{
int x;
public:
A() { cout << "A's constructor called " << endl; }
};

class B
{
static A a;
public:
B() { cout << "B's constructor called " << endl; }
static A getA() { return a; }
};

A B::a; // definition of a

int main()
{
// static member 'a' is accessed without any object of B
A a = B::getA();
return 0;
}

Output:
A's constructor called

Static Member Functions:


By declaring a function member as static, you make it independent of any particular object of the class.
A static member function can be called even if no objects of the class exist and the static functions are
accessed using only the class name and the scope resolution operator ::.

A static member function can only access static data member, other static member functions and any
other functions from outside the class.

Static member functions have a class scope and they do not have access to the this pointer of the class.
You could use a static member function to determine whether some objects of the class have been
created or not.

Let us try the following example to understand the concept of static function members −
#include <iostream>
using namespace std;
class Box {
public:
static int objectCount;

Box(double l = 2.0, double b = 2.0, double h = 2.0) {


cout <<"Constructor called." << endl;
length = l;
breadth = b;
height = h;

objectCount++;
}
double Volume() {
return length * breadth * height;
}
static int getCount() {
return objectCount;
}

private:
double length;
double breadth;
double height;
};

int Box::objectCount = 0;

int main(void) {
cout << "Inital Stage Count: " << Box::getCount() << endl;

Box Box1(3.3, 1.2, 1.5); // Declare box1


Box Box2(8.5, 6.0, 2.0); // Declare box2

cout << "Final Stage Count: " << Box::getCount() << endl;
return 0;
}
Output:
Inital Stage Count: 0
Constructor called.
Constructor called.
Final Stage Count: 2

A static member function is a special member function, which is used to access only static data
members, any other normal data member cannot be accessed through static member function.

Consider the example:


#include <iostream>
using namespace std;
class Demo
{
private:
static int X;
static int Y;

public:
static void Print()
{
cout <<"Value of X: " << X << endl;
cout <<"Value of Y: " << Y << endl;
}
};

int Demo :: X =10;


int Demo :: Y =20;

int main()
{
Demo OB;
//accessing class name with object name
cout<<"Printing through object name:"<<endl;
OB.Print();

//accessing class name with class name


cout<<"Printing through class name:"<<endl;
Demo::Print();
return 0;
}
Output
Printing through object name:
Value of X: 10
Value of Y: 20
Printing through class name:
Value of X: 10
Value of Y: 20

Some interesting facts about static member functions in C++


1) static member functions do not have this pointer.
For example, following program fails in compilation with error “`this’ is unavailable for static
member functions “
#include<iostream>
class Test {
static Test * fun() {
return this; // compiler error
}
};

int main()
{
getchar();
return 0;
}
2) A static member function cannot be virtual.
3) Member function declarations with the same name and the name parameter-type-list cannot
be overloaded if any of them is a static member function declaration.
For example, following program fails in compilation with error “‘void Test::fun()’ and `static
void Test::fun()’ cannot be overloaded “
#include<iostream>
class Test {
static void fun() {}
void fun() {} // compiler error
};

int main()
{
getchar();
return 0;
}
4) A static member function can not be declared const, volatile, or const volatile.
For example, following program fails in compilation with error “static member function
`static void Test::fun()’ cannot have `const’ method qualifier ”
#include<iostream>
class Test {
static void fun() const { // compiler error
return;
}
};

int main()
{
getchar();
return 0;
}

Array of Objects:
We can have arrays of variables that are of the type class. Such variables are called arrays of object.
Consider the following class definition:
class employee {
char name[30];
float age;
public:
void getdata(void);
void putdata(void);
};
The identifier employee is a user-defined data type and can be used to create objects that relate to
different categories of the employees. Example:
employee manager[3];
employee foreman[15];
employee worker[75];

The array manager contains three objects (managers), namely, manager[0], manager[1] and manager[2],
of type employee class. Similarly, the foreman array contains 15 objects(formans) and the worker array
contains 75 objects (workers);

Objects as a function argument and returning object from a function:


Like any other data type, an object may be used as a function argument. This can be done in two ways:
• A copy of the entire object is passed to the function. (pass by value)
• Only the address of the object is transferred to the function. (pass by reference)

Passing an Object as argument


To pass an object as an argument we write the object name as the argument while calling the
function the same way we do it for other variables.
Syntax:
function_name(object_name);

Example: In this Example there is a class which has an integer variable ‘a’ and a function ‘add’ which
takes an object as argument. The function is called by one object and takes another as an argument.
Inside the function, the integer value of the argument object is added to that on which the ‘add’
function is called. In this method, we can pass objects as an argument and alter them.

// C++ program to show passing of objects to a function


#include <bits/stdc++.h>
using namespace std;
class Example {
public:
int a;

// This function will take an object as an argument


void add(Example E)
{
a = a + E.a;
}
};

int main()
{
Example E1, E2;
E1.a = 50;
E2.a = 100;
cout << "Initial Values \n";
cout << "Value of object 1: " << E1.a << "\n& object 2: " << E2.a;

// Passing object as an argument to function add()


E2.add(E1);

// Changed values after passing object as argument


cout << "New values \n";
cout << "Value of object 1: " << E1.a<< "\n& object 2: " << E2.a;
return 0;
}
Output
Initial Values
Value of object 1: 50
& object 2: 100

New values
Value of object 1: 50
& object 2: 150

Returning Object as argument


Syntax:
object = return object_name;
Example: In the above example we can see that the add function does not return any value since its
return-type is void. In the following program the add function returns an object of type
‘Example'(i.e., class name) whose value is stored in E3.
In this example, we can see both the things that are how we can pass the objects as well as return
them. When the object E3 calls the add function it passes the other two objects namely E1 & E2 as
arguments. Inside the function, another object is declared which calculates the sum of all the three
variables and returns it to E3.
This code and the above code is almost the same, the only difference is that this time the add
function returns an object whose value is stored in another object of the same class ‘Example’ E3.
Here the value of E1 is displayed by object1, the value of E2 by object2 and value of E3 by object3.

// C++ program to show passing of objects to a function


#include <bits/stdc++.h>
using namespace std;

class Example {
public:
int a;
Example add(Example Ea, Example Eb)
{
Example Ec;
Ec.a = Ea.a + Eb.a;
return Ec;
}
};
int main()
{
Example E1, E2, E3;
E1.a = 50;
E2.a = 100;
E3.a = 0;
cout << "Initial Values \n";
cout << "Value of object 1: " << E1.a<< ", \nobject 2: " << E2.a
<< ", \nobject 3: " << E3.a<< "\n";

// Passing object as an argument to function add()


E3 = E3.add(E1, E2);

// Changed values after passing object as an argument


cout << "New values \n";
cout << "Value of object 1: " << E1.a<< ", \nobject 2: " << E2.a
<< ", \nobject 3: " << E3.a<< "\n";

return 0;
}
Output
Initial Values
Value of object 1: 50,
object 2: 100,
object 3: 0
New values
Value of object 1: 50,
object 2: 100,
object 3: 150

Function Overloading and Ambiguity:


When the compiler is unable to decide which function is to be invoked among the overloaded
function, this situation is known as function overloading.
When the compiler shows the ambiguity error, the compiler does not run the program.
Causes of Function Overloading:
• Type Conversion.
• Function with default arguments.
• Function with pass by reference.
Type Conversion:
Example:
#include<iostream>
using namespace std;
void fun(int);
void fun(float);

void fun(int i)
{
std::cout << "Value of i is : " <<i<< std::endl;
}
void fun(float j)
{
std::cout << "Value of j is : " <<j<< std::endl;
}
int main()
{
fun(12);
fun(1.2);
return 0;
}
The above example shows an error "call of overloaded 'fun(double)' is ambiguous". The fun(10)
will call the first function. The fun(1.2) calls the second function according to our prediction. But, this
does not refer to any function as in C++, all the floating point constants are treated as double not as a
float. If we replace float to double, the program works. Therefore, this is a type conversion from float
to double.

Function with Default Arguments:


Example:
#include<iostream>
using namespace std;
void fun(int);
void fun(int,int);

void fun(int i)
{
std::cout << "Value of i is : " <<i<< std::endl;
}
void fun(int a,int b=9)
{
std::cout << "Value of a is : " <<a<< std::endl;
std::cout << "Value of b is : " <<b<< std::endl;
}
int main()
{
fun(12);
return 0;
}
The above example shows an error "call of overloaded 'fun(int)' is ambiguous". The fun(int a, int b=9)
can be called in two ways: first is by calling the function with one argument, i.e., fun(12) and another
way is calling the function with two arguments, i.e., fun(4,5). The fun(int i) function is invoked with
one argument. Therefore, the compiler could not be able to select among fun(int i) and fun(int a,int b=9).

Function with pass by reference:


Example:
#include <iostream>
using namespace std;
void fun(int);
void fun(int &);
int main()
{
int a=10;
fun(a); // error, which fun()?
return 0;
}
void fun(int x)
{
std::cout << "Value of x is : " <<x<< std::endl;
}
void fun(int &b)
{
std::cout << "Value of b is : " <<b<< std::endl;
}
The above example shows an error "call of overloaded 'fun(int&)' is ambiguous". The first function
takes one integer argument and the second function takes a reference parameter as an argument. In this
case, the compiler does not know which function is needed by the user as there is no syntactical
difference between the fun(int) and fun(int &).

Friend class and function in C++:


Friend Class: A friend class can access private and protected members of other class in which it is
declared as friend. It is sometimes useful to allow a particular class to access private members of other
class.
For example, a LinkedList class may be allowed to access private members of Node.
class Node {
private:
int key;
Node* next;
/* Other members of Node Class */
// Now class LinkedList can access private members of Node
friend class LinkedList;
};

Friend Function: Like friend class, a friend function can be given a special grant to access private
and protected members. A friend function can be:
a) A member of another class
b) A global function

Following are some important points about friend functions and classes:
1. Friends should be used only for limited purpose. too many functions or external classes are
declared as friends of a class with protected or private data, it lessens the value of encapsulation
of separate classes in object-oriented programming.
2. Friendship is not mutual. If class A is a friend of B, then B doesn’t become a friend of A
automatically.
3. Friendship is not inherited
4. The function is not in the scope of the class to which it has been declared as a friend.
5. It cannot be called using the object as it is not in the scope of that class.
6. It can be invoked like a normal function without using the object.
7. It can be declared either in the private or the public part.
8. The concept of friends is not there in Java.
A simple and complete C++ program to demonstrate friend Class:
#include <iostream>
class A {
private:
int a;

public:
A() { a = 0; }
friend class B; // Friend Class
};

class B {
private:
int b;

public:
void showA(A& x)
{
// Since B is friend of A, it can access
// private members of A
std::cout << "A::a=" << x.a;
}
};

int main()
{
A a;
B b;
b.showA(a);
return 0;
}
Output:
A::a=0

A simple and complete C++ program to demonstrate friend functions:


Let's see a simple example when the function is friendly to two classes:
#include <iostream>
using namespace std;
class B; // forward declaration.
class A
{
int x;
public:
void setdata(int i)
{
x=i;
}
friend void min(A,B); // friend function.
};
class B
{
int y;
public:
void setdata(int i)
{
y=i;
}
friend void min(A,B); // friend function
};
void min(A a,B b)
{
if(a.x<=b.y)
std::cout << a.x << std::endl;
else
std::cout << b.y << std::endl;
}
int main()
{
A a;
B b;
a.setdata(10);
b.setdata(20);
min(a,b);
return 0;
}
Output:
10

Another Example:
#include <iostream>
class B;

class A {
public:
void showB(B&);
};
class B {
private:
int b;

public:
B() { b = 0; }
friend void A::showB(B& x); // Friend function
};
void A::showB(B& x)
{
// Since showB() is friend of B, it can
// access private members of B
std::cout << "B::b = " << x.b;
}
int main()
{
A a;
B x;
a.showB(x);
return 0;
}
Output:
B::b = 0

A simple and complete C++ program to demonstrate global friend:


Let's see the simple example of C++ friend function used to print the length of a box.
#include <iostream>
using namespace std;
class Box
{
private:
int length;
public:
Box(): length(0) { }
friend int printLength(Box); //friend function
};
int printLength(Box b)
{
b.length += 10;
return b.length;
}
int main()
{
Box b;
cout<<"Length of box: "<< printLength(b)<<endl;
return 0;
}
Output:
Length of box: 10

Another Example:
#include <iostream>

class A {
int a;

public:
A() { a = 0; }

// global friend function


friend void showA(A&);
};

void showA(A& x)
{
// Since showA() is a friend, it can access
// private members of A
std::cout << "A::a=" << x.a;
}

int main()
{
A a;
showA(a);
return 0;
}
Output:
A::a = 0

new and delete operators in C++ for dynamic memory:


Dynamic memory allocation in C/C++ refers to performing memory allocation manually by
programmer. Dynamically allocated memory is allocated on Heap and non-static and local variables get
memory allocated on Stack.

What are applications?


• One use of dynamically allocated memory is to allocate memory of variable size which is
not possible with compiler allocated memory except variable length arrays.
• The most important use is flexibility provided to programmers. We are free to allocate and
deallocate memory whenever we need and whenever we don’t need anymore. There are
many cases where this flexibility helps. Examples of such cases are Linked List, Tree, etc.

How is it different from memory allocated to normal variables?


For normal variables like “int a”, “char str[10]”, etc, memory is automatically allocated and deallocated.
For dynamically allocated memory like “int *p = new int[10]”, it is programmers responsibility to
deallocate memory when no longer needed. If programmer doesn’t deallocate memory, it
causes memory leak (memory is not deallocated until program terminates).

How is memory allocated/deallocated in C++?


C uses malloc() and calloc() function to allocate memory dynamically at run time and uses free()
function to free dynamically allocated memory. C++ supports these functions and also has two
operators new and delete that perform the task of allocating and freeing the memory in a better and
easier way.

new operator
The new operator denotes a request for memory allocation on the Free Store. If sufficient memory is
available, new operator initializes the memory and returns the address of the newly allocated and
initialized memory to the pointer variable.
• Syntax to use new operator: To allocate memory of any data type, the syntax is:
pointer-variable = new data-type;

Here, pointer-variable is the pointer of type data-type. Data-type could be any built-in data type
including array or any user defined data types including structure and class.
Example:
// Pointer initialized with NULL Then request memory for the variable
int *p = NULL;
p = new int;
OR
// Combine declaration of pointer and their assignment
int *p = new int;

Initialize memory: We can also initialize the memory using new operator:
pointer-variable = new data-type(value);
Example:
int *p = new int(25);
float *q = new float(75.25);

Allocate block of memory: new operator is also used to allocate a block(an array) of memory of
type data-type.
pointer-variable = new data-type[size];
where size(a variable) specifies the number of elements in an array.
Example:
int *p = new int[10]
Dynamically allocates memory for 10 integers continuously of type int and returns pointer to the first
element of the sequence, which is assigned to p(a pointer). p[0] refers to first element, p[1] refers to
second element and so on.
Normal Array Declaration vs Using new
There is a difference between declaring a normal array and allocating a block of memory using new.
The most important difference is, normal arrays are deallocated by compiler (If array is local, then
deallocated when function returns or completes). However, dynamically allocated arrays always remain
there until either they are deallocated by programmer or program terminates.

What if enough memory is not available during runtime?


If enough memory is not available in the heap to allocate, the new request indicates failure by throwing
an exception of type std::bad_alloc, unless “nothrow” is used with the new operator, in which case it
returns a NULL pointer. Therefore, it may be good idea to check for the pointer variable produced by
new before using it program.

int *p = new(nothrow) int;


if (!p)
{
cout << "Memory allocation failed\n";
}

delete operator
Since it is programmer’s responsibility to deallocate dynamically allocated memory, programmers are
provided delete operator by C++ language.
Syntax:
// Release memory pointed by pointer-variable
delete pointer-variable;
Here, pointer-variable is the pointer that points to the data object created by new.
Examples:
delete p;
delete q;
To free the dynamically allocated array pointed by pointer-variable, use following form of delete:
// Release block of memory pointed by pointer-variable
delete[] pointer-variable;
Example:
// It will free the entire array pointed by p.
delete[] p;
// C++ program to illustrate dynamic allocation
// and deallocation of memory using new and delete
#include <iostream>
using namespace std;

int main ()
{
int* p = NULL;

// Request memory for the variable using new operator


p = new(nothrow) int;
if (!p)
cout << "allocation of memory failed\n";
else
{
// Store value at allocated address
*p = 29;
cout << "Value of p: " << *p << endl;
}
// Request block of memory using new operator
float *r = new float(75.25);

cout << "Value of r: " << *r << endl;

int n = 5;
int *q = new(nothrow) int[n];

if (!q)
cout << "allocation of memory failed\n";
else
{
for (int i = 0; i < n; i++)
q[i] = i+1;

cout << "Value store in block of memory: ";


for (int i = 0; i < n; i++)
cout << q[i] << " ";
}

// freed the allocated memory


delete p;
delete r;

// freed the block of allocated memory


delete[] q;

return 0;
}
Output:
Value of p: 29
Value of r: 75.25
Value store in block of memory: 1 2 3 4 5

Pointer to a C++ Class:


A pointer to a C++ class is done exactly the same way as a pointer to a structure and to access members
of a pointer to a class you use the member access operator -> operator, just as you do with pointers to
structures. Also as with all pointers, you must initialize the pointer before using it.

Let us try the following example to understand the concept of pointer to a class −
#include <iostream>
using namespace std;
class Box {
public:
Box(double l = 2.0, double b = 2.0, double h = 2.0) {
cout <<"Constructor called." << endl;
length = l;
breadth = b;
height = h;
}
double Volume() {
return length * breadth * height;
}

private:
double length;
double breadth;
double height;
};
int main(void) {
Box Box1(3.3, 1.2, 1.5);
Box Box2(8.5, 6.0, 2.0);
Box *ptrBox;
ptrBox = &Box1;
cout << "Volume of Box1: " << ptrBox->Volume() << endl;

ptrBox = &Box2;
cout << "Volume of Box2: " << ptrBox->Volume() << endl;
return 0;
}
Output:
Constructor called.
Constructor called.
Volume of Box1: 5.94
Volume of Box2: 102

Overloading New and Delete operator in C++:


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.

Syntax for overloading the new operator :


void* operator new(size_t size);
The overloaded new operator receives size of type size_t, which specifies the number of bytes of
memory to be allocated. The return type of the overloaded new must be void*.The overloaded
function returns a pointer to the beginning of the block of memory allocated.

Syntax for overloading the delete operator :


void operator delete(void*);
The function receives a parameter of type void* which has to be deleted. Function should not return
anything.

NOTE: Both overloaded new and delete operator functions are static members by default. Therefore,
they don’t have access to this pointer .

Overloading new and delete operator for a specific class:


// CPP program to demonstrate Overloading new and delete operators for a
//specific class
#include<iostream>
#include<stdlib.h>
using namespace std;

class student
{
string name;
int age;
public:
student()
{
cout<< "Constructor is called\n" ;
}
student(string name, int age)
{
this->name = name;
this->age = age;
}
void display()
{
cout<< "Name:" << name << endl;
cout<< "Age:" << age << endl;
}
void * operator new(size_t size)
{
cout<< "Overloading new operator with size: " << size << endl;
void * p = ::operator new(size);
//void * p = malloc(size); will also work fine
return p;
}

void operator delete(void * p)


{
cout<< "Overloading delete operator " << endl;
free(p);
}
};

int main()
{
student * p = new student("Yash", 24);
p->display();
delete p;
}
Overloading new operator with size: 16
Constructor is called
Name:Yash
Age:24
Overloading delete operator

NOTE: In the above new overloaded function, we have allocated dynamic memory through new
operator, but it should be global new operator otherwise it will go in recursion
void *p = new student(); // this will go in recursion asnew will be overloaded again and again
void *p = ::new student(); // this is correct

Global overloading of new and delete operator


CPP
// CPP program to demonstrate Global overloading of new and delete operator
#include<iostream>
#include<stdlib.h>

using namespace std;


void * operator new(size_t size)
{
cout << "New operator overloading " << endl;
void * p = malloc(size);
return p;
}

void operator delete(void * p)


{
cout << "Delete operator overloading " << endl;
free(p);
}
int main()
{
int n = 5, i;
int * p = new int[3];

for (i = 0; i<n; i++)


p[i]= i;

cout << "Array: ";


for(i = 0; i<n; i++)
cout << p[i] << " ";

cout << endl;

delete p;
}
Output :
New operator overloading
Array: 0 1 2 3 4
Delete operator overloading
NOTE: In the code above, in new overloaded function we cannot allocate memory using ::new
int[5] as it will go in recursion. We need to allocate memory using malloc only.

Why to overload new and delete?


1. The overloaded new operator function can accept arguments; therefore, a class can have multiple
overloaded new operator functions. This gives the programmer more flexibility in customizing
memory allocation for objects. For example:
void *operator new(size_t size, char c)
{
void *ptr;
ptr = malloc(size);
if (ptr!=NULL)
*ptr = c;
return ptr;
}
main()
{
char *ch = new('#') char;
}

2. NOTE: Code will not only allocate memory for single character but will also initialize the allocated
memory with # character.
3. Overloaded new or delete operators also provide Garbage Collection for class’s object.
4. Exception handling routine can be added in overloaded new operator function.
5. Sometimes you want operators new and delete to do something customized that the compiler-
provided versions don’t offer. For example, You might write a custom operator delete that overwrites
deallocated memory with zeros in order to increase the security of application data.
6. We can use realloc() function in new function to re-allocate memory dynamically.
7. Overloaded new operator also enables programmers to squeeze some extra performance out of their
programs. For example, In a class, to speed up the allocation of new nodes, a list of deleted nodes is
maintained so that their memory can be reused when new nodes are allocated. In this case, the
overloaded delete operator will add nodes to the list of deleted nodes and the overloaded new operator
will allocate memory from this list rather than from the heap to speedup memory allocation. Memory
from the heap can be used when the list of deleted nodes is empty.

You might also like