0% found this document useful (0 votes)
12 views18 pages

07 Constructor and Destructor

Uploaded by

nanigir651
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)
12 views18 pages

07 Constructor and Destructor

Uploaded by

nanigir651
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/ 18

SHRI SHANKARACHARYA TECHNICAL CAMPUS

Constructors
What are Constructors?
• A constructor is a special member function that is automatically called when an object
of a class is created. Its primary purpose is to initialize the object’s attributes and
allocate resources necessary for the object's operation.
Reasons for Using Constructors:
1. Automatic Initialization: Constructors allow for automatic setup of objects when
they are created, ensuring that they start their life in a valid state.
2. Overloading: Constructors can be overloaded, which means you can have multiple
constructors with different parameters. This provides flexibility in object creation.
3. Encapsulation of Logic: Initialization logic can be encapsulated in constructors,
making the code cleaner and easier to maintain.
4. Resource Management: If your class manages resources dynamically (like memory,
file handles, etc.), constructors can allocate those resources.
5. Constructor Delegating: C++11 introduced the ability to have constructors call other
constructors of the same class, reducing code duplication.
Constructor:
class MyClass {
public:
int x;
// Constructor with one parameter
MyClass(int value) : x(value) {
// Constructor body
}
};
// Usage
MyClass obj(10); // Automatically calls MyClass(int value)

SOMESH KUMAR DEWANGAN DEPARTMENT OF CSE 1


SHRI SHANKARACHARYA TECHNICAL CAMPUS

Destructors
What are Destructors?
• A destructor is a special member function that is called when an object goes out of
scope or is explicitly deleted. Its main purpose is to free resources that the object may
have acquired during its lifetime.
Reasons for Using Destructors:
1. Resource Deallocation: Destructors ensure that any resources (memory, file handles,
sockets, etc.) that were allocated during the life of the object are properly released.
2. Prevention of Memory Leaks: If a class allocates memory on the heap, the
destructor can be used to deallocate that memory, thereby preventing memory leaks.
3. Cleanup Logic: Just like constructors can encapsulate initialization logic, destructors
can encapsulate cleanup logic, promoting better resource management practices.
4. Automatic Invocation: Destructors are automatically called when an object’s lifetime
ends, ensuring consistent cleanup without the need for explicit deallocation.
Destructor:
class MyClass {
public:
int* ptr;

// Constructor
MyClass() {
ptr = new int; // Dynamically allocating memory
}

// Destructor
~MyClass() {
delete ptr; // Freeing the allocated memory
}
};
// Usage
{
MyClass obj; // At the end of this scope, the destructor will automatically be called

SOMESH KUMAR DEWANGAN DEPARTMENT OF CSE 2


SHRI SHANKARACHARYA TECHNICAL CAMPUS

}
Copy Constructor
In C++, a copy constructor is a special constructor that initializes a new object as a copy of an
existing object. The copy constructor is used when an object is passed by value, returned
from a function, or explicitly constructed from another object. The default copy constructor
provided by the compiler performs a shallow copy, meaning it copies the values of the
member variables. However, if the class allocates dynamic memory, you might want to define
your own copy constructor to perform a deep copy.
• The copy constructor is called when a new object is created from an existing object.
• If a class contains pointers to dynamically allocated resources, a deep copy must be
implemented; otherwise, you can end up with multiple objects sharing the same
memory space, leading to resource management issues like memory leaks and double
deletions.
• Always define a destructor when managing dynamic memory in a class.
Simple Copy Constructor:
We define a simple class Point that represents a point in 2D space. The copy constructor will
handle copying the member variables.
#include <iostream>
class Point {
private:
int x, y;

public:
// Constructor
Point(int xVal, int yVal) : x(xVal), y(yVal) {}

// Copy Constructor
Point(const Point& p) {
x = p.x;
y = p.y;
std::cout << "Copy Constructor called!" << std::endl;
}

SOMESH KUMAR DEWANGAN DEPARTMENT OF CSE 3


SHRI SHANKARACHARYA TECHNICAL CAMPUS

void display() const {


std::cout << "Point(" << x << ", " << y << ")" << std::endl;
}
};

int main() {
Point p1(10, 20); // Default Constructor
Point p2 = p1; // Copy Constructor is called
p1.display();
p2.display();

return 0;
}
Output:
Copy Constructor called!
Point(10, 20)
Point(10, 20)
Copy Constructor with Dynamic Memory:
We create a class String that manages a dynamically allocated character array. Here, we need
to ensure that a deep copy is made in the copy constructor to avoid multiple objects pointing
to the same memory.
#include <iostream>
#include <cstring>
class String {
private:
char* str;

public:
// Constructor
String(const char* s) {
str = new char[strlen(s) + 1];
strcpy(str, s);
}

SOMESH KUMAR DEWANGAN DEPARTMENT OF CSE 4


SHRI SHANKARACHARYA TECHNICAL CAMPUS

// Copy Constructor for deep copy


String(const String& s) {
str = new char[strlen(s.str) + 1]; // Allocate new memory
strcpy(str, s.str); // Copy the string
std::cout << "Copy Constructor called!" << std::endl;
}

// Destructor
~String() {
delete[] str; // Free the allocated memory
}

void display() const {


std::cout << str << std::endl;
}
};
int main() {
String str1("Hello, World!"); // Default Constructor
String str2 = str1; // Copy Constructor is called
str1.display();
str2.display();

return 0;
}
Output:

Copy Copy Constructor called!


Hello, World!
Hello, World!

SOMESH KUMAR DEWANGAN DEPARTMENT OF CSE 5


SHRI SHANKARACHARYA TECHNICAL CAMPUS

Dynamic Constructor
In C++, a dynamic constructor is a constructor that allocates memory dynamically for an
object during its execution using the new keyword. This is particularly useful when the size
of the data structure cannot be determined at compile time.
Here are two examples that illustrate the use of dynamic constructors in C++.
Dynamic Array using a Constructor:
We will create a class that represents a dynamic array. The constructor will take the size of
the array as an argument and allocate memory for it dynamically.
#include <iostream>
class DynamicArray {
private:
int* arr;
int size;

public:
// Dynamic constructor
DynamicArray(int s) {
size = s;
arr = new int[size]; // Allocate memory for the array
}

// Function to set values in the dynamic array


void setValues() {
for (int i = 0; i < size; i++) {
arr[i] = i + 1; // Assign values 1, 2, ..., size
}
}

// Function to display the values of the dynamic array


void display() {
for (int i = 0; i < size; i++) {
std::cout << arr[i] << " ";

SOMESH KUMAR DEWANGAN DEPARTMENT OF CSE 6


SHRI SHANKARACHARYA TECHNICAL CAMPUS

}
std::cout << std::endl;
}

// Destructor to free allocated memory


~DynamicArray() {
delete[] arr; // Deallocate memory
}
};

int main() {
DynamicArray myArray(5); // Create a dynamic array of size 5
myArray.setValues(); // Set values in the array
myArray.display(); // Display values

return 0;
}
Output:
12345
Class with Dynamic Memory Allocation for Objects:
We will create a class Person and use a dynamic constructor to allocate memory for a string
that holds the person's name.
#include <iostream>
#include <cstring>

class Person {
private:
char* name;

public:
// Dynamic constructor
Person(const char* n) {
name = new char[strlen(n) + 1]; // Allocate memory for the name

SOMESH KUMAR DEWANGAN DEPARTMENT OF CSE 7


SHRI SHANKARACHARYA TECHNICAL CAMPUS

strcpy(name, n); // Copy the name into the allocated memory


}

// Function to display the name


void display() {
std::cout << "Name: " << name << std::endl;
}

// Destructor to free allocated memory


~Person() {
delete[] name; // Deallocate memory
}
};

int main() {
Person p1("Alice"); // Create an object with dynamic memory allocation
p1.display(); // Display the name

return 0;
}
Output:
Name: Alice
Explanation
1. In the First Program, we created a DynamicArray class that dynamically allocates an
array based on the size provided. The destructor is used to free the allocated memory.
2. In the second Program, we created a Person class that dynamically allocates memory
for a string to store a person's name. Again, a destructor is used to clean up the
memory.

SOMESH KUMAR DEWANGAN DEPARTMENT OF CSE 8


SHRI SHANKARACHARYA TECHNICAL CAMPUS

Explicit Constructor:
In C++, an explicit constructor is one that is declared with the explicit keyword. This
keyword prevents the compiler from using the constructor for implicit type
conversions, which can help avoid unexpected behaviors in your code.
Here's a brief explanation followed by two examples.
When to Use explicit
• Implicit conversions can lead to unexpected results or bugs, especially when
performing assignments or function calls.
• By marking a constructor as explicit, you ensure that it can only be explicitly called
(i.e., with a direct object creation syntax).
Basic Usage of Explicit Constructor:
#include <iostream>
class Box {
public:
// Explicit constructor
explicit Box(int length) : length(length) {}

int getVolume() const {


return length * length * length; // Volume of a cube
}

private:
int length;
};

int main() {
Box box1(3); // Direct initialization (OK)
std::cout << "Volume of box1: " << box1.getVolume() << std::endl;

// Box box2 = 5; // This line would cause a compilation error


Box box2 = Box(5); // Explicitly calling the constructor (OK)
std::cout << "Volume of box2: " << box2.getVolume() << std::endl;

SOMESH KUMAR DEWANGAN DEPARTMENT OF CSE 9


SHRI SHANKARACHARYA TECHNICAL CAMPUS

return 0;
}
the Box class has an explicit constructor. Trying to create a Box using implicit
conversion (e.g., Box box2 = 5;) would result in a compilation error. Instead, you
must explicitly create a Box object like Box box2 = Box(5);.
Preventing Implicit Conversion:
#include <iostream>
class Fraction {
public:
// Explicit constructor
explicit Fraction(int numerator) : numerator(numerator), denominator(1) {}

void display() const {


std::cout << numerator << "/" << denominator << std::endl;
}
private:
int numerator;
int denominator;
};

void printFraction(const Fraction& f) {


f.display();
}
int main() {
Fraction f1(3); // Direct initialization (OK)
printFraction(f1); // Print Fraction
// printFraction(5); // This line would cause a compilation error
printFraction(Fraction(5)); // Explicitly creating a Fraction (OK)
return 0;
}
The Fraction class has an explicit constructor. If you try to pass an integer directly to
the printFraction function (line commented out), it would cause a compilation error,
thus preventing implicit conversion. Instead, you must create a Fraction object

SOMESH KUMAR DEWANGAN DEPARTMENT OF CSE 10


SHRI SHANKARACHARYA TECHNICAL CAMPUS

explicitly.

SOMESH KUMAR DEWANGAN DEPARTMENT OF CSE 11


SHRI SHANKARACHARYA TECHNICAL CAMPUS

Destructor:
In C++, a destructor is a special member function that is invoked when an object of a
class goes out of scope or is explicitly deleted. The main purpose of a destructor is to
release resources that the object may have acquired during its lifetime, such as
dynamically allocated memory, file handles, etc. A destructor has the same name as
the class but is prefixed with a tilde (~). It does not take any parameters and does not
return a value.
1. Automatic Call: Destructors are called automatically when an object's lifetime ends
(when it goes out of scope or is explicitly deleted).
2. No Parameters or Return Type: Destructors do not take parameters and do not
return a value.
3. Single Destructor: A class can only have one destructor.
4. Resource Management: Destructors are essential for resource management,
especially when dealing with dynamic memory, file descriptors, and other resources
that require explicit cleanup.
Basic Destructor:
We will demonstrate a destructor that releases dynamically allocated memory.
#include <iostream>
class MyClass {
private:
int* data;
public:
// Constructor to allocate memory
MyClass(int size) {
data = new int[size]; // dynamically allocate array of integers
std::cout << "Memory allocated for " << size << " integers." << std::endl;
}
// Destructor to free the allocated memory
~MyClass() {
delete[] data; // release allocated memory
std::cout << "Memory freed." << std::endl;
}

SOMESH KUMAR DEWANGAN DEPARTMENT OF CSE 12


SHRI SHANKARACHARYA TECHNICAL CAMPUS

};
int main() {
MyClass obj(5); // Create an object of MyClass
// Memory is allocated for 5 integers

// The destructor will be called automatically when obj goes out of scope
return 0;
}
Output:
Memory allocated for 5 integers.
Memory freed.
Destructor with File Handling:
In this program destructor that closes an open file when the object goes out of scope.
#include <iostream>
#include <fstream>
class FileHandler {
private:
std::fstream file;
public:
// Constructor opens a file
FileHandler(const std::string& filename) {
file.open(filename, std::ios::out | std::ios::app);
if (file.is_open()) {
std::cout << "File opened: " << filename << std::endl;
} else {
std::cerr << "Error opening file: " << filename << std::endl;
}
}
// Destructor closes the file
~FileHandler() {
if (file.is_open()) {
file.close();
std::cout << "File closed." << std::endl;

SOMESH KUMAR DEWANGAN DEPARTMENT OF CSE 13


SHRI SHANKARACHARYA TECHNICAL CAMPUS

}
}
// Example method to write to the file
void writeToFile(const std::string& data) {
if (file.is_open()) {
file << data << std::endl;
}
}
};

int main() {
{
FileHandler fh("example.txt");
fh.writeToFile("Hello, World!");
} // FileHandler goes out of scope here and the destructor is called

// At this point, the file "example.txt" is closed automatically


return 0;
}
Output:
File opened: example.txt
File closed.

Constructor and Destructor with Static Member


In C++, constructors and destructors are special member functions that are called
when an object is created and destroyed, respectively. Static members are shared
among all instances of a class. They are not tied to any particular instance but belong
to the class itself.
Basic Static Member with Constructor and Destructor:
We'll have a class Counter that keeps track of the number of instances created and
destroyed using static member variables.
#include <iostream>
class Counter {

SOMESH KUMAR DEWANGAN DEPARTMENT OF CSE 14


SHRI SHANKARACHARYA TECHNICAL CAMPUS

private:
static int count; // Static member to keep track of count

public:
// Constructor increments the count
Counter() {
count++;
std::cout << "Constructor called. Current count: " << count << std::endl;
}
// Destructor decrements the count
~Counter() {
count--;
std::cout << "Destructor called. Current count: " << count << std::endl;
}
// Static function to get the current count
static int getCount() {
return count;
}
};

// Define and initialize the static member


int Counter::count = 0;
int main() {
std::cout << "Program started." << std::endl;

Counter obj1; // Create first object


{
Counter obj2; // Create second object in a block
} // obj2 goes out of scope here

Counter obj3; // Create third object

std::cout << "Final count: " << Counter::getCount() << std::endl;

SOMESH KUMAR DEWANGAN DEPARTMENT OF CSE 15


SHRI SHANKARACHARYA TECHNICAL CAMPUS

return 0; // obj1 and obj3 go out of scope here


}
Output:
Program started.
Constructor called. Current count: 1
Constructor called. Current count: 2
Destructor called. Current count: 1
Constructor called. Current count: 2
Final count: 2
Destructor called. Current count: 1
Destructor called. Current count: 0
Explanation:
• The Counter class has a static member count that tracks the number of instances.
• The constructor increments count whenever a new object is created, while the
destructor decrements it when an object is destroyed.
• The static member count is shared across all instances of Counter.

Static Member for Unique ID Generation:


We introduce another static member to demonstrate generating unique IDs for each
instance.
#include <iostream>
class User {
private:
static int idCounter; // Static member to generate unique IDs
int userID; // Non-static member to hold the user's ID
public:
// Constructor assigns a unique ID to userID
User() {
userID = ++idCounter; // Increment the counter for a new ID
std::cout << "User created with ID: " << userID << std::endl;
}
// Destructor

SOMESH KUMAR DEWANGAN DEPARTMENT OF CSE 16


SHRI SHANKARACHARYA TECHNICAL CAMPUS

~User() {
std::cout << "User with ID: " << userID << " is being destroyed." << std::endl;
}
// Function to get the current ID count
static int getIdCount() {
return idCounter;
}
};
// Define and initialize the static member
int User::idCounter = 0;
int main() {
std::cout << "Creating users..." << std::endl;
User user1;
User user2;
{
User user3; // This goes out of scope here
}
std::cout << "Total users created: " << User::getIdCount() << std::endl;
return 0; // user1 and user2 go out of scope here
}
Output:

Copy Creating users...


User created with ID: 1
User created with ID: 2
User created with ID: 3
User with ID: 3 is being destroyed.
Total users created: 3
User with ID: 2 is being destroyed.
User with ID: 1 is being destroyed.
Explanation:
• The User class has a static integer idCounter that keeps track of how many users have
been created, helping to assign unique IDs.

SOMESH KUMAR DEWANGAN DEPARTMENT OF CSE 17


SHRI SHANKARACHARYA TECHNICAL CAMPUS

• Every time a User object is created, the constructor increments idCounter and assigns
the new value to the instance's userID.
• The destructor prints a message when a user object is destroyed, showing which user
is being destroyed.

SOMESH KUMAR DEWANGAN DEPARTMENT OF CSE 18

You might also like