0% found this document useful (0 votes)
133 views42 pages

Important Topics On C++ by Deepak Mitra

The document discusses several important topics in C++ including: 1. The size of an empty class is not zero but 1 byte to ensure each object has a unique memory address. 2. Multiple objects of an empty class will each have a unique address. 3. The size of a void pointer depends on the platform but is typically 4 bytes for 32-bit and 8 bytes for 64-bit. 4. Constructors in C++ initialize objects and there are default, parameterized, and copy constructors. Parameterized constructors allow passing arguments to initialize objects.

Uploaded by

Md Asif Alam
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)
133 views42 pages

Important Topics On C++ by Deepak Mitra

The document discusses several important topics in C++ including: 1. The size of an empty class is not zero but 1 byte to ensure each object has a unique memory address. 2. Multiple objects of an empty class will each have a unique address. 3. The size of a void pointer depends on the platform but is typically 4 bytes for 32-bit and 8 bytes for 64-bit. 4. Constructors in C++ initialize objects and there are default, parameterized, and copy constructors. Parameterized constructors allow passing arguments to initialize objects.

Uploaded by

Md Asif Alam
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
You are on page 1/ 42

Important Topics in C++

Empty Classes

Why is the size of an empty class not zero in C++?

#include<iostream>
using namespace std;

class Empty {};

int main()
{
cout << sizeof(Empty);
return 0;
}
Output:

Size of an empty class is not zero. It is 1 byte generally. It is nonzero to ensure that the two different
objects will have different addresses. To an object of an empty class, 1 byte is allocated by compiler for
unique address identification. So, if a class have multiple objects they can have different unique memory
location. Suppose, if a class does not have any size, what would be stored on the memory location?
That’s the reason when we create an object of an empty class in C++ program, it needs some memory to
get stored, and the minimum amount of memory that can be reserved is 1 byte.

So, if we create multiple objects of an empty class, every object will have unique address.

See the following example.

#include<iostream>
using namespace std;

class Empty { };

int main()
{
Empty a, b;

if (&a == &b)
cout << "Both object have same address"<< endl;
else
cout << "Both object have unique address" << endl;

1
Important Topics in C++

return 0;
}
Output:

Fine

For the same reason (different objects should have different addresses), “new” always returns pointers
to distinct objects. See the following example.

#include<iostream>
using namespace std;

class Empty { };

int main()
{
Empty* p1 = new Empty;
Empty* p2 = new Empty;

if (p1 == p2)
cout << "impossible " << endl;
else
cout << "Fine " << endl;

return 0;
}
Output:

Fine

Now guess the output of following program (This is tricky)

#include<iostream>
using namespace std;

class Empty { };

class Derived: Empty { int a; };

int main()
{
cout << sizeof(Derived);
return 0;
}

2
Important Topics in C++

Output (with GCC compiler):

Note that the output is not greater than 4. There is an interesting rule that says that an empty base class
need not be represented by a separate byte. So compilers are free to make optimization in case of
empty base classes. As an excercise, try the following program on your compiler.

#include <iostream>
using namespace std;

class Empty
{};

class Derived1 : public Empty


{};

class Derived2 : virtual public Empty


{};

class Derived3 : public Empty


{
char c;
};

class Derived4 : virtual public Empty


{
char c;
};

class Dummy
{
char c;
};

int main()
{
cout << "sizeof(Empty) " << sizeof(Empty) << endl;
cout << "sizeof(Derived1) " << sizeof(Derived1) << endl;
cout << "sizeof(Derived2) " << sizeof(Derived2) << endl;
cout << "sizeof(Derived3) " << sizeof(Derived3) << endl;
cout << "sizeof(Derived4) " << sizeof(Derived4) << endl;
cout << "sizeof(Dummy) " << sizeof(Dummy) << endl;

return 0;
}

3
Important Topics in C++

Size of Empty Class in C++ with virtual function :

If an empty class contain virtual function, even though there is no data members in the class, its size will
not be 1 byte but 4 byte because of virtual pointer i.e. VPTR. Virtual pointer size on 32 bit platform is 4
bytes and on 64 bit it is 8 bytes.

When we make a function as a virtual, compiler automatically set a hidden VPTR as a class data member
field. So, no longer a class is an empty class that contains virtual function in C++.

For example size of below class that contain virtual function will be 4 bytes.

class ClassWithVirtualFunctions{

public:
virtual void display(){
}
};

int main(){

cout << sizeof(EmptyClassWithFunctions)<<endl;

return 0;
}

What is Size of VOID pointer on multiple platforms?

Size of void pointer on 16 bit Platform is : 2 bytes , on 32 bit : 4 bytes and on 64 bit : 8 bytes. Size of
void* is of same size in C/C++, but, the size of void pointer is platform dependent.

On 32 bit platform Size of void* is 4 byte. In fact, any kind of pointer we consider i.e. int , char or float
etc. all have same size and size could be 4 bytes or 8 bytes depend upon platform we are using i.e.32 bit
or 64 bit etc.

Actually, whatever are pointer types, that store only address of the variables they point to, whatever it
is int, float or char etc. so, size for all pointers would be same.

If we consider 32 bit platform, size of all pointers will be of 4 bytes size. And if it is 64 bit, it would be of
8 byte.

NOTE:

4
Important Topics in C++

How to find size of void pointer?

To find a size of void pointer variables, we can use sizeof operator in c or c++ program. On window 64
bit machine, generally, we should find 32 bit and 64 bit support. So, if we want to check the size of void
pointer in 64 bit or 32 bit platform then we need to check the project properties for platform x86(32 bit)
or x64(64 bit) in visual studio IDE. Then we can see the size of void* as 4 or 8 byte depending upon
configuration for 32 bit or 64 bit respectively.

int main(){

void *a;

printf("Size - void pointer:%d",sizeof(a));

return 0;
}

Below are default functions provided by compiler in C++ language if not implemented in a class by a
software developer.

 Default constructor
 Copy constructor
 Assignment operator
 Destructor

Constructors in C++

What is constructor?
A constructor is a member function of a class which initializes objects of a class. In C++, Constructor is
automatically called when object(instance of class) create. It is special member function of the class.

How constructors are different from a normal member function?

A constructor is different from normal functions in following ways:

 Constructor has same name as the class itself


 Constructors don’t have return type
 A constructor is automatically called when an object is created.

If we do not specify a constructor, C++ compiler generates a default constructor for us (expects no
parameters and has an empty body).

5
Important Topics in C++

Types of Constructors

Default Constructors:

Default constructor is the constructor which doesn’t take any argument. It has no parameters.

// Cpp program to illustrate the


// concept of Constructors
#include <iostream>
using namespace std;

class construct {
public:
int a, b;

// Default Constructor
construct()
{
a = 10;
b = 20;
}
};

int main()
{
// Default constructor called automatically
// when the object is created
construct c;
cout << "a: " << c.a << endl
<< "b: " << c.b;
return 1;
}
Output:

a: 10

b: 20

Note: Even if we do not define any constructor explicitly, the compiler will automatically provide a
default constructor implicitly.

6
Important Topics in C++

Parameterized Constructors

It is possible to pass arguments to constructors. Typically, these arguments help initialize an object when
it is created. To create a parameterized constructor, simply add parameters to it the way you would to
any other function. When you define the constructor’s body, use the parameters to initialize the object.

// CPP program to illustrate


// parameterized constructors
#include <iostream>
using namespace std;

class Point {
private:
int x, y;

public:
// Parameterized Constructor
Point(int x1, int y1)
{
x = x1;
y = y1;
}

int getX()
{
return x;
}
int getY()
{
return y;
}
};

int main()
{
// Constructor called
Point p1(10, 15);

// Access values assigned by constructor


cout << "p1.x = " << p1.getX() << ", p1.y = " << p1.getY();

return 0;
}
Output:

p1.x = 10, p1.y = 15

7
Important Topics in C++

When an object is declared in a parameterized constructor, the initial values have to be passed as
arguments to the constructor function. The normal way of object declaration may not work. The
constructors can be called explicitly or implicitly.

Example e = Example(0, 50); // Explicit call

Example e(0, 50); // Implicit call

Uses of Parameterized constructor:

It is used to initialize the various data elements of different objects with different values when they are
created.

It is used to overload constructors.

Can we have more than one constructors in a class?


Yes, It is called Constructor Overloading.

Copy Constructor

A copy constructor is a member function which initializes an object using another object of the same
class.

Whenever we define one or more non-default constructors( with parameters ) for a class, a default
constructor( without parameters ) should also be explicitly defined as the compiler will not provide a
default constructor in this case. However, it is not necessary but it’s considered to be the best practice
to always define a default constructor.

// Illustration
#include "iostream"
using namespace std;

class point {
private:
double x, y;

public:
// Non-default Constructor & default Constructor
point (double px, double py) {
x = px, y = py;
}
};

int main(void) {

8
Important Topics in C++

// Define an array of size 10 & of type point


// This line will cause error
point a[10];

// Remove above line and program will compile without error


point b = point(5, 6);
}
Output:

Error: point (double px, double py): expects 2 arguments, 0 provided

Copy Constructor in C++

What is a copy constructor?

A copy constructor is a member function which initializes an object using another object of the same
class. A copy constructor has the following general function prototype:

ClassName (const ClassName &old_obj);

Following is a simple example of copy constructor.

#include<iostream>
using namespace std;

class Point
{
private:
int x, y;
public:
Point(int x1, int y1) { x = x1; y = y1; }

// Copy constructor
Point(const Point &p2) {x = p2.x; y = p2.y; }

int getX() { return x; }


int getY() { return y; }
};

int main()
{
Point p1(10, 15); // Normal constructor is called here
Point p2 = p1; // Copy constructor is called here

// Let us access values assigned by constructors


cout << "p1.x = " << p1.getX() << ", p1.y = " << p1.getY();
cout << "\np2.x = " << p2.getX() << ", p2.y = " << p2.getY();

9
Important Topics in C++

return 0;
}
Output:

p1.x = 10, p1.y = 15

p2.x = 10, p2.y = 15

When is copy constructor called?


In C++, a Copy Constructor may be called in following cases:
1. When an object of the class is returned by value.
2. When an object of the class is passed (to a function) by value as an argument.
3. When an object is constructed based on another object of the same class.
4. When the compiler generates a temporary object.

It is, however, not guaranteed that a copy constructor will be called in all these cases, because the C++
Standard allows the compiler to optimize the copy away in certain cases,

When is user-defined copy constructor needed?

If we don’t define our own copy constructor, the C++ compiler creates a default copy constructor for
each class which does a member-wise copy between objects. The compiler created copy constructor
works fine in general. We need to define our own copy constructor only if an object has pointers or any
runtime allocation of the resource like file handle, a network connection..etc.

Default constructor does only shallow copy.

Deep copy is possible only with user defined copy constructor. In user defined copy constructor,
we make sure that pointers (or references) of copied object point to new memory locations.

10
Important Topics in C++

Copy constructor vs Assignment Operator

Which of the following two statements call copy constructor and which one calls assignment
operator?

MyClass t1, t2;

MyClass t3 = t1; // ----> (1)

t2 = t1; // -----> (2)

Copy constructor is called when a new object is created from an existing object, as a copy of the existing
object. Assignment operator is called when an already initialized object is assigned a new value from
another existing object. In the above example (1) calls copy constructor and (2) calls assignment
operator.

Write an example class where copy constructor is needed?


Following is a complete C++ program to demonstrate use of Copy constructor. In the following String
class, we must write copy constructor.

#include<iostream>
#include<cstring>
using namespace std;

class String
{
private:
char *s;
int size;

11
Important Topics in C++

public:
String(const char *str = NULL); // constructor
~String() { delete [] s; }// destructor
String(const String&); // copy constructor
void print() { cout << s << endl; } // Function to print string
void change(const char *); // Function to change
};

String::String(const char *str)


{
size = strlen(str);
s = new char[size+1];
strcpy(s, str);
}

void String::change(const char *str)


{
delete [] s;
size = strlen(str);
s = new char[size+1];
strcpy(s, str);
}

String::String(const String& old_str)


{
size = old_str.size;
s = new char[size+1];
strcpy(s, old_str.s);
}

int main()
{
String str1("CDAC CoE ");
String str2 = str1;

str1.print(); // what is printed ?


str2.print();

str2.change("CDAC CoE Gaya");

str1.print(); // what is printed now ?


str2.print();
return 0;
}

12
Important Topics in C++

What would be the problem if we remove copy constructor from above code?
If we remove copy constructor from the above program, we don’t get the expected output. The changes
made to str2 reflect in str1 as well which is never expected.

#include<iostream>
#include<cstring>
using namespace std;

class String
{
private:
char *s;
int size;
public:
String(const char *str = NULL); // constructor
~String() { delete [] s; }// destructor
void print() { cout << s << endl; }
void change(const char *); // Function to change
};

String::String(const char *str)


{
size = strlen(str);
s = new char[size+1];
strcpy(s, str);
}

void String::change(const char *str)


{
delete [] s;
size = strlen(str);
s = new char[size+1];
strcpy(s, str);
}

int main()
{
String str1("CDAC CoE ");
String str2 = str1;

str1.print(); // what is printed ?


str2.print();

str2.change("CDAC CoE Gaya");

str1.print(); // what is printed now ?


str2.print();

13
Important Topics in C++

return 0;
}
Can we make copy constructor private?
Yes, a copy constructor can be made private. When we make a copy constructor private in a class,
objects of that class become non-copyable. This is particularly useful when our class has pointers or
dynamically allocated resources. In such situations, we can either write our own copy constructor like
above String example or make a private copy constructor so that users get compiler errors rather than
surprises at runtime.
Why argument to a copy constructor must be passed as a reference?

A copy constructor is called when an object is passed by value. Copy constructor itself is a function. So if
we pass an argument by value in a copy constructor, a call to copy constructor would be made to call
copy constructor which becomes a non-terminating chain of calls. Therefore compiler doesn’t allow
parameters to be passed by value.

Why argument to a copy constructor should be const?

When we create our own copy constructor, we pass an object by reference and we generally pass it as a
const reference.

One reason for passing const reference is, we should use const in C++ wherever possible so that objects
are not accidentally modified. This is one good reason for passing reference as const, but there is more
to it. For example, predict the output of following C++ program. Assume that copy elision is not done by
compiler.

Note : In the context of the C++ programming language, return value optimization (RVO) is a compiler
optimization that involves eliminating the temporary object created to hold a function's return
value. RVO is particularly notable for being allowed to change the observable behaviour of the
resulting program by the C++ standard

#include<iostream>
using namespace std;

class Test
{
/* Class data members */
public:
Test(Test &t) { /* Copy data members from t*/}

14
Important Topics in C++

Test() { /* Initialize data members */ }


};

Test fun()
{
cout << "fun() Called\n";
Test t;
return t;
}

int main()
{
Test t1;
Test t2 = fun();
return 0;
}

Output:

Compiler Error in line "Test t2 = fun();"

The program looks fine at first look, but it has compiler error. If we add const in copy constructor, the
program works fine, i.e., we change copy constructor to following.

Test(const Test &t) { cout << "Copy Constructor Called\n"; }

Or if we change the line “Test t2 = fun();” to following two lines, then also the program works fine.

Test t2;

t2 = fun();

The function fun() returns by value. So the compiler creates a temporary object which is copied to t2
using copy constructor in the original program (The temporary object is passed as an argument to copy
constructor). The reason for compiler error is, compiler created temporary objects cannot be bound to
non-const references and the original program tries to do that. It doesn’t make sense to modify
compiler created temporary objects as they can die any moment.

Copy Constructors are called when

When copies of objects are made

A copy constructor is called whenever a new variable is created from an object. This happens in the
following cases (but not in assignment).

15
Important Topics in C++

A variable is declared which is initialized from another object, eg,

 Person q("Mickey"); // constructor is used to build q.


 Person r(p); // copy constructor is used to build r.
 Person p = q; // copy constructor is used to initialize in declaration.
 p = q; // Assignment operator, no constructor or copy constructor.

A value parameter is initialized from its corresponding argument.

 f(p); // copy constructor initializes formal value parameter.

An object is returned by a function.

C++ calls a copy constructor to make a copy of an object in each of the above cases. If there is no copy
constructor defined for the class, C++ uses the default copy constructor which copies each field, ie,
makes a shallow copy.

Don't write a copy constructor if shallow copies are ok

If the object has no pointers to dynamically allocated memory, a shallow copy is probably sufficient.
Therefore the default copy constructor, default assignment operator, and default destructor are ok and
you don't need to write your own.

If you need a copy constructor, you also need a destructor and operator=

If you need a copy constructor, it's because you need something like a deep copy, or some other
management of resources. Thus is is almost certain that you will need a destructor and override the
assignment operator.

Copy constructor syntax

The copy constructor takes a reference to a const parameter. It is const to guarantee that the copy
constructor doesn't change it, and it is a reference because a value parameter would require making a
copy, which would invoke the copy constructor, which would make a copy of its parameter, which would
invoke the copy constructor, which ...

Here is an example of a copy constructor for the Point class, which doesn't really need one because the
default copy constructor's action of copying fields would work fine, but it shows how it works.

//=== file Point.h =============================================

16
Important Topics in C++

class Point {
public:
...
Point(const Point& p); // copy constructor
...
//=== file Point.cpp ==========================================
...
Point::Point(const Point& p) {
x = p.x;
y = p.y;
}
...
//=== file my_program.cpp ====================================
...
Point p; // calls default constructor
Point s = p; // calls copy constructor.
p = s; // assignment, not copy constructor.

Difference between copy constructor and assignment

A copy constructor is used to initialize a newly declared variable from an existing variable. This makes a
deep copy like assignment, but it is somewhat simpler:

 There is no need to test to see if it is being initialized from itself.


 There is no need to clean up (eg, delete) an existing value (there is none).
 A reference to itself is not returned.

When should we write our own copy constructor?

C++ compiler provide default copy constructor (and assignment operator) with class. When we don’t
provide implementation of copy constructor (and assignment operator) and tries to initialize object with
already initialized object of same class then copy constructor gets called and copies members of class
one by one in target object.

The problem with default copy constructor (and assignment operator) is – When we have members
which dynamically gets initialized at run time, default copy constructor copies this members with
address of dynamically allocated memory and not real copy of this memory. Now both the objects
points to the same memory and changes in one reflects in another object, Further the main disastrous
effect is, when we delete one of this object other object still points to same memory, which will be
dangling pointer, and memory leak is also possible problem with this approach.

17
Important Topics in C++

Hense, in such cases, we should always write our own copy constructor (and assignment operator).

Copy constructor vs assignment operator in C++

#include<iostream>
#include<stdio.h>

using namespace std;

class Test
{
public:
Test() {}
Test(const Test &t)
{
cout<<"Copy constructor called "<<endl;
}

Test& operator = (const Test &t)


{
cout<<"Assignment operator called "<<endl;
return *this;
}
};

// Driver code
int main()
{
Test t1, t2;
t2 = t1;
Test t3 = t1;
getchar();
return 0;
}

Output:

 Assignment operator called


 Copy constructor called

Copy constructor is called when a new object is created from an existing object, as a copy of the existing
object (see this G-Fact). And assignment operator is called when an already initialized object is assigned
a new value from another existing object.

 t2 = t1; // calls assignment operator, same as "t2.operator=(t1);"

18
Important Topics in C++

 Test t3 = t1; // calls copy constructor, same as "Test t3(t1);"

Constructor Delegation in C++

Sometimes it is useful for a constructor to be able to call another constructor of the same class. This
feature, called Constructor Delegation, was introduced in C++ 11.

// A C++ program to demonstrate need of


// constructor delegation.
#include <iostream>
using namespace std;

class A {
int x, y, z;

public:
A()
{
x = 0;
y = 0;
z = 0;
}
A(int z)
{
// The below two lines are redundant
x = 0;
y = 0;

/* Only initialize z by passing an argument,


while all the other arguments are
initialized the same way they were,
as in the previous constructor*/
this->z = z;
}

void show()
{
cout << x << '\n'
<< y << '\n'
<< z;
}
};

int main()
{
A obj(3);
obj.show();

19
Important Topics in C++

return 0;
}

Solving above redundant code problem using init()


We can see in the above example that the constructors of the above class, despite having different
signatures, have first two lines of code common between them, leading to code duplication. One
solution to solution to avoid this situation would have been the creation of an init function that can be
called from both the constructors.

// Program to demonstrate use of init() to


// avoid redundant code.
#include <iostream>
using namespace std;

class A {
int x, y, z;

// init function to initialize x and y


void init()
{
x = 0;
y = 0;
}

public:
A()
{
init();
z = 0;
}
A(int z)
{
init();
this->z = z;
}

void show()
{
cout << x << '\n'
<< y << '\n'
<< z;
}
};

20
Important Topics in C++

int main()
{
A obj(3);
obj.show();
return 0;
}
Solving above redundant code problem using constructor delegation()

While the usage of an init() function eliminates duplicate code, it still has its own drawbacks. First, it’s
not quite as readable, as it adds a new function and several new function calls. Second, because init() is
not a constructor, it can be called during the normal program flow, where member variables may
already be set and dynamically allocated memory may already be allocated. This means init() needs to
be additionally complex in order to handle both the new initialization and re-initialization cases
properly.

However, C++ Constructor delegation provides an elegant solution to handle this problem, by allowing
us to call a constructor by placing it in the initializer list of other constructors. The following program
demonstrates how it is done:

// Program to demonstrate constructor delegation


// in C++
#include <iostream>
using namespace std;
class A {
int x, y, z;

public:
A()
{
x = 0;
y = 0;
z = 0;
}

// Constructor delegation
A(int z) : A()
{
this->z = z; // Only update z
}

void show()
{
cout << x << '\n'
<< y << '\n'

21
Important Topics in C++

<< z;
}
};
int main()
{
A obj(3);
obj.show();
return 0;
}
It is very important to note that constructor delegation is different from calling a constructor from inside
the body of another constructor, which is not recommended because doing so creates another object
and initializes it, without doing anything to the object created by the constructor that called it.

Can a constructor be private in C++ ?

A constructor is a special member function of a class which initializes objects of a class. In C++,
constructor is automatically called when object of a class is created.

By default, constructors are defined in public section of class. So, question is can a constructor be
defined in private section of class ?
Answer : Yes, Constructor can be defined in private section of class

How to use Constructors in private section?

 Using Friend Class : If we want that class should not be instantiated by anyone else but only by a
friend class.

// CPP program to demonstrate usage of


// private constructor
#include <iostream>
using namespace std;

// class A
class A{
private:
A(){
cout << "constructor of A\n";
}
friend class B;
};

// class B, friend of class A


class B{
public:

22
Important Topics in C++

B(){
A a1;
cout << "constructor of B\n";
}
};

// Driver program
int main(){
B b1;
return 0;
}

Output:

constructor of A

constructor of B

If you comment the line friend class B, you will encounter below error:

test1.cpp: In constructor ‘B::B()’:

test1.cpp:9:5: error: ‘A::A()’ is private

A(){

test1.cpp:19:11: error: within this context

A a1;

 Using Singleton design pattern: When we want to design a singleton class. This means instead of
creating several objects of class, the system is driven by a single object or a very limited number of
objects.
 Named Constructor Idiom : Since constructor has same name as of class, different constructors are
differentiated by their parameter list, but if numbers of constructors is more, then implementation
can become error prone.

With the Named Constructor Idiom, you declare all the class’s constructors in the private or protected
sections, and then for accessing objects of class, you create public static functions.

For example, consider below CPP program

// CPP program to demonstrate

23
Important Topics in C++

// ambiguous nature of constructor


// with same no of parameters of same type
#include <iostream>
using namespace std;
class Point
{
public:

// Rectangular coordinates
Point(float x, float y);

// Polar coordinates (radius and angle)


Point(float r, float a);

// error: ‘Point::Point(float, float)’ cannot


// be overloaded
};
int main()
{
// Ambiguous: Which constructor to be called ?
Point p = Point(5.7, 1.2);
return 0;
}
This problem can be resolved by Named Constructor Idiom. The above CPP program can be improved as
following :

// CPP program to demonstrate


// named constructor idiom
#include <iostream>
#include <cmath>
using namespace std;
class Point
{
private:
float x1, y1;
Point(float x, float y)
{
x1 = x;
y1 = y;
};
public:
// polar(radius, angle)
static Point Polar(float, float);

// rectangular(x, y)
static Point Rectangular(float, float);
void display();

24
Important Topics in C++

};

// utility function for displaying of coordinates


void Point :: display()
{
cout << "x :: " << this->x1 <<endl;
cout << "y :: " << this->y1 <<endl;
}

// return polar coordinates


Point Point :: Polar(float x, float y)
{
return Point(x*cos(y), x*sin(y));
}

// return rectangular coordinates


Point Point :: Rectangular(float x, float y)
{
return Point(x,y);
}
int main()
{
// Polar coordinates
Point pp = Point::Polar(5.7, 1.2);
cout << "polar coordinates \n";
pp.display();

// rectangular coordinates
Point pr = Point::Rectangular(5.7,1.2);
cout << "rectangular coordinates \n";
pr.display();
return 0;
}

Output :
polar coordinates
x :: 2.06544
y :: 5.31262
rectangular coordinates
x :: 5.7
y :: 1.2

What is conversion constructor in C++?

In C++, if a class has a constructor which can be called with a single argument, then this constructor
becomes conversion constructor because such a constructor allows automatic conversion to the class
being constructed.

25
Important Topics in C++

#include <iostream>

class MyClass {
int a, b;

public:
MyClass(int i)
{
a = i;
b = i;
}
void display()
{
std::cout << " a = " << a << " b = " << b << "\n";
}
};

int main()
{
MyClass object(10);
object.display();

// Single parameter conversion constructor is invoked.


object = 20;
object.display();
return 0;
}
Output:

a = 10 b = 10

a = 20 b = 20

Conversion Constructors: There are constructors that convert types of its parameter into a type of the
class. The compiler uses these constructors to perform implicit class-type conversions. These
conversions are made by invoking the corresponding constructor with matches the list of values/objects
that are assigned to the object.

This previous example only deals with one parameter, to extend it to several parameters i.e., extended
initializer lists or braced-init-lists. That is, we enclose the parameters to be passed to it inside a pair of
curly braces ({}).

Example with Multiple Parameters:

#include <iostream>

26
Important Topics in C++

class MyClass {
int a, b;

public:
MyClass(int i, int y)
{
a = i;
b = y;
}
void display()
{
std::cout << " a = " << a << " b = " << b << "\n";
}
};

int main()
{
MyClass object(10, 20);
object.display();

// Multiple parameterized conversion constructor is invoked.


object = { 30, 40 };
object.display();
return 0;
}

Output:

a = 10 b = 20

a = 30 b = 40

Note:

 Extended intializer lists are available in C++11 and on.


 We can directly try assigning a extended initializer list to a object when it is being created.
 An implicit class-type conversion feature of a constructor doesn’t affect its normal behaviour.
 Using the explict function-specifier for a constructor removes the implicit conversions using that
constructor

Usage of conversion constructor

In return value of a function:

27
Important Topics in C++

When the return type of a function is a class, instead of returning a object, we can return a braced-init-
list, now since the return type is a class instance, a object of that class is created with the braced-init-list,
given that the class has a corresponding conversion constructor.

Example:

MyClass create_object(int x, int y)


{
return {x, y};
}

This function create_object will return a MyClass object with a and b values as the x and y passed to the
function.

As a parameter to a function:

When a function’s parameter type is of a class, instead of passing a object to the function, we can pass
a braced-init-list to the function as the actual parameter, given that the class has a corresponding
conversion constructor.

An example :

void display_object(MyClass obj)


{
obj.display();
}

// This function is invoked in the main function with a braced-init-list with two integers as the
parameter.
// e.g. :
// display_object({10, 20});

Note: This function display_object creates a new class instance of MyClass called obj and will call its
member function display().

-------------------------------------------------------------------------------------------------------------------------------------
The two parts in which our memory is divided. These parts are as follows:

28
Important Topics in C++

 stack - Memory from the stack is used by all the members which are declared inside functions. Note
that main is also a function.
 heap - This memory is unused and can be used to dynamically allocate the memory at runtime.

new

The new operator is used to allocate memory at runtime. The memory is allocated in bytes.

Let's first see how to allocate a variable dynamically.

int *ptr = new int;

By writing new int, we allocated the space in memory required by an integer. Then we assigned the
address of that memory to an integer pointer ptr.

We assign value to that memory as follows:

*ptr = 4;

Thus, we allocated that much space in memory that would be required by an int and then assigned
the address of that memory to a pointer ptr and assigned the memory a value 4.

We can initialize a variable while dynamical allocation in the following two ways.

 int *ptr = new int (4);


 int *ptr = new int {4};

Let's see an example.

#include <iostream>

int main()
{
int *ptr = new int;
*ptr = 4;
std::cout << *ptr << std::endl;
return 0;
}

Dynamically Allocating Arrays

The main use of the concept of dynamic memory allocation is for allocating arrays when we have to
declare an array by specifying its size but are not sure about the size.

Consider a situation when we want the user to enter the name but are not sure about the number of
characters in the name that the user will enter. In that case, we will declare an array of characters for

29
Important Topics in C++

the name with some array size such that the array size should be sufficient enough to hold any name
entered. Suppose we declared the array with the array size 30 as follows.

char name[30];

And if the user enters the name having only 12 characters, then the rest of the memory space which was
allocated to the array at the time of its declaration would become waste, thus unnecessary consuming
the memory.

In this case, we will be using the new operator to dynamically allocate the memory at runtime. We use
the new operator as follows.

char *arr = new char[length];

Let's see an example to understand its use.

#include <iostream>

using namespace std;

int main()
{
int length, sum = 0;
cout << "Enter the number of students in the group" << endl;
cin >> length;
int *marks = new int[length];
cout << "Enter the marks of the students" << endl;
for( int i = 0; i < length; i++ ) // entering marks of students
{
cin >> *(marks+i);
}
for( int i = 0; i < length; i++ ) // calculating sum
{
sum += *(marks+i);
}
cout << "sum is " << sum << endl;
return 0;
}

In this example, we are calculating the sum of the marks of all the students of a group. Since different
groups have a different number of students, therefore we are asking the number of students ( i.e.the
size of the array ) every time we are running the program. In this example, the user entered the size as
4.
int *marks = new int[length];

30
Important Topics in C++

We declared an array of integer and allocated it some space in memory dynamically equal to the size
which would be occupied by length number of integers. Thus it is allocated a space equal to 'length *
(size of 1 integer)' and assigned the address of the assigned memory to the pointer marks. The rest of
the steps must be clear to you.

We call this array dynamic because it is being assigned memory when the program runs. We made this
possible by using the new operator. This dynamic array is being allocated memory from heap unlike
other fixed arrays which are provided memory from stack. We can give any size to these dynamic arrays
and there is no limitation to it.

delete

Suppose we allocated some memory to a variable dynamically and then we realize that the variable is
not needed anymore in the program. In that case, we need to free the memory which we had assigned
to that variable. For that, we use the delete operator.

It is advised to free the dynamically allocated memory after the program finishes so that it becomes
available for future use.

To delete the memory assigned to a variable, we simply need to write the following code.

delete ptr;

Here ptr is the pointer to the dynamically allocated variable.

There is nothing much to understand in this. The delete operator simply returns the memory allocated
back to the operating system so that it can be used again. Let's look at an example.

#include <iostream>

int main()
{
int *ptr = new int;
*ptr = 4;
std::cout << *ptr << std::endl;
delete ptr;
return 0;
}

31
Important Topics in C++

After printing the value 4, we deleted the pointer i.e. deleted the address of the allocated memory thus
freeing it.

Once deleted, a pointer will point to deallocated memory and will be called a dangling pointer. If we
further try to delete a dangling pointer, we will get some undefined behavior.

Deleting Array

To delete an array which has been allocated in this way, we write the following code.

delete[] ptr;

Here ptr is a pointer to an array which has been dynamically allocated.

#include <iostream>

using namespace std;

int main()
{
int length, sum = 0;
cout << "Enter the number of students in the group" << endl;
cin >> length;
int *marks = new int[length];
cout << "Enter the marks of the students" << endl;
for( int i = 0; i < length; i++ ) // entering marks of students
{
cin >> *(marks+i);
}
for( int i = 0; i < length; i++ ) // calculating sum
{
sum += *(marks+i);
}
cout << "sum is " << sum << endl;
delete[] marks;
return 0;
}

We just wrote delete[ ] marks; at the end of the program to release the memory which was dynamically
allocated using new.

Dynamic Memory Allocation for Objects

We can also dynamically allocate objects.

32
Important Topics in C++

As we know that Constructor is a member function of a class which is called whenever a new object is
created of that class. It is used to initialize that object. Destructor is also a class member function which
is called whenever the object goes out of scope.

Destructor is used to release the memory assigned to the object. It is called in these conditions.

When a local object goes out of scope

For a global object, operator is applied to a pointer to the object of the class

We again use pointers while dynamically allocating memory to objects.

Let's see an example of array of objects.

#include <iostream>

using namespace std;

class A
{
public:
A() {
cout << "Constructor" << endl;
}
~A() {
cout << "Destructor" << endl;
}
};

int main()
{
A* a = new A[4];
delete [] a; // Delete array
return 0;
}
Output

The Constructor will be called four times since we are allocating memory to four objects of the class 'A'.
The Destructor will also be called four times during each of these objects.

How to make a C++ class whose objects can only be dynamically allocated?

The problem is to create a class such that the non-dynamic allocation of object causes compiler error.
For example, create a class ‘Test’ with following rules.

33
Important Topics in C++

Test t1; // Should generate compiler error

Test *t3 = new Test; // Should work fine

The idea is to create a private destructor in the class. When we make a private destructor, the compiler
would generate a compiler error for non-dynamically allocated objects because compiler need to
remove them from stack segment once they are not in use.
Since compiler is not responsible for deallocation of dynamically allocated objects (programmer should
explicitly deallocate them), compiler won’t have any problem with them. To avoid memory leak, we
create a friend function destructTest() which can be called by users of class to destroy objects.

#include <iostream>
using namespace std;

// A class whose object can only be dynamically created


class Test
{
private:
~Test() { cout << "Destroying Object\n"; }
public:
Test() { cout << "Object Created\n"; }
friend void destructTest(Test* );
};

// Only this function can destruct objects of Test


void destructTest(Test* ptr)
{
delete ptr;
cout << "Object Destroyed\n";
}

int main()
{
/* Uncommenting following following line would cause compiler error */
// Test t1;

// create an object
Test *ptr = new Test;

// destruct the object to avoid memory leak


destructTest(ptr);

return 0;
}
Object Created

34
Important Topics in C++

Destroying Object

Object Destroyed

If we don’t want to create a friend function, we can also overload delete and delete[] operators in Test,
this way we don’t have to call a specific function to delete dynamically allocated objects.

How to restrict dynamic allocation of objects in C++?

C++ programming language allows both auto(or stack allocated) and dynamically allocated objects. In
java & C#, all objects must be dynamically allocated using new.
C++ supports stack allocated objects for the reason of runtime efficiency. Stack based objects are
implicitly managed by C++ compiler. They are destroyed when they go out of scope and dynamically
allocated objects must be manually released, using delete operator otherwise memory leak occurs. C++
doesn’t support automatic garbage collection approach used by languages such as Java & C#.

How do we achieve following behavior from a class ‘Test’ in C++?

Test* t = new Test; // should produce compile time error

Test t; // OK

The idea of is to keep new operator function private so that new cannot be called. See the following
program. Objects of ‘Test’ class cannot be created using new as new operator function is private in
‘Test’. If we uncomment the 2nd line of main(), the program would produce compile time error.

#include <iostream>
using namespace std;

// Objects of Test can not be dynamically allocated


class Test
{
// Notice this, new operator function is private
void* operator new(size_t size);
int x;
public:
Test() { x = 9; cout << "Constructor is called\n"; }
void display() { cout << "x = " << x << "\n"; }
~Test() { cout << "Destructor is executed\n"; }
};

int main()
{
// Uncommenting following line would cause a compile time error.

35
Important Topics in C++

// Test* obj=new Test();


Test t; // Ok, object is allocated at compile time
t.display();
return 0;
} // object goes out of scope, destructor will be called
Output:

Constructor is called

x=9

Destructor is executed

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 operator

36
Important Topics in C++

// 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 = ::new student();
//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

37
Important Topics in C++

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 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++)

38
Important Topics in C++

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?

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;
}
NOTE: Code will not only allocate memory for single character but will also initialize the allocated
memory with # character.

 Overloaded new or delete operators also provide Garbage Collection for class’s object.
 Exception handling routine can be added in overloaded new operator function.
 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.
 We can use realloc() function in new function to re-allocate memory dynamically.

39
Important Topics in C++

 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.

Important Points/properties: new and delete operator overloading

 Overloaded new operator can accept additional arguments except size to be allocated.
 In one class delete operator can be overloaded only once.
 In one class new operator can be overloaded multiple times.
 When we create object of the class with “new” operator the class overloaded new function will
get called with the object size as a parameter. e.g. CustomMemory object = new
CustomMemory.

Example
#include<iostream>
using namespace std;

class CustomMemory{

public:

void* operator new(size_t objectSize);//Overloaded new


void operator delete(void* ptr); //Overloaded delete
};

void* CustomMemory::operator new(size_t objectSize)


{
cout<<"Custom memory allocation"<<endl;
//May Write costume memory allocation algorithm here
return malloc(objectSize);

}
void CustomMemory::operator delete(void* ptr)
{
cout<<"Custom memory de- allocation"<<endl;
free(ptr);
}

int main(){

40
Important Topics in C++

// call overloaded new from the class


CustomMemory *obj = new CustomMemory();
// call overloaded delete
delete obj;
}

Example

#include<iostream>
using namespace std;

class CustomMemory{
int i;// size of int is 4 byte
public:
CustomMemory(){
cout<<"Constructor"<<"\n";
}
~CustomMemory(){
cout<<"Destructor"<<"\n";
}
//Overloaded new
void* operator new(size_t objectSize) {
cout<<"Custom memory allocation"<<"\n";
//Write allocation algorithm here
return malloc(objectSize);
}
//Overloaded 2 arguments new operator
void* operator new(size_t objectSize, int x) {
cout<<"Custom 2 argument memory allocation"<<"\n";
CustomMemory *ptr =(CustomMemory*)malloc(objectSize);
ptr->i = x;
return ptr;
}

//Overloaded delete
void operator delete(void* ptr) {
cout<<"Custom memory de- allocation"<<"\n";
free(ptr);
}
void Display(){
cout<<"Value of i ="<<i<<"\n";
}
};
int main(){

// call overloaded new from the class


CustomMemory *obj = new CustomMemory();

41
Important Topics in C++

// call overloaded delete


delete obj;

//overloaded 2 argument new


CustomMemory * ptr = new(5)CustomMemory();
ptr->Display();
delete ptr;
}

42

You might also like