Skip to content

Instantly share code, notes, and snippets.

@twentyse7en
Last active December 5, 2020 14:27
Show Gist options
  • Save twentyse7en/bb4467503c20576cc0065006eecc22ca to your computer and use it in GitHub Desktop.
Save twentyse7en/bb4467503c20576cc0065006eecc22ca to your computer and use it in GitHub Desktop.
Constructor and Destructor

Constructor

You might have already know what is a constructor is, so why read this. Here you deep dive into different types of constructors, copy constructor is one good stuff to have a look. credits@gfg

Index

Details

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.

  • 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).

Types of constructor

Let us understand the types of constructors in C++ by taking a real-world example. Suppose you went to a shop to buy a marker. When you want to buy a marker, what are the options? The first one you go to a shop and say give me a marker. So just saying give me a marker mean that you did not set which brand name and which color, you didn’t mention anything just say you want a marker. So when we said just I want a marker so whatever the frequently sold marker is there in the market or in his shop he will simply hand over that. And this is what a default constructor is! The second method you go to a shop and say I want a marker a red in color and XYZ brand. So you are mentioning this and he will give you that marker. So in this case you have given the parameters. And this is what a parameterized constructor is! Then the third one you go to a shop and say I want a marker like this(a physical marker on your hand). So the shopkeeper will see that marker. Okay, and he will give a new marker for you. So copy of that marker. And that’s what copy constructor is!

Default Constructor

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

#include <iostream>
using namespace std;
 
class construct 
{
public:
    int a, b;
 
    // Default Constructor
    construct()
    {
        a = 10;
        b = 20;
    }
};

Parameterized Constructors

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

#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;
    }
};

copy constructor

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

#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(); 

	return 0; 
}

So why would you ever need this ?

#include <iostream>
using namespace std;

class xboxController
{
    public:
        int *m_Id;

    public:
        xboxController(int id)
        {
            m_Id = new int(id);
        }

        void get_Id()
        {
            cout << *m_Id << endl;
        }

        void set_Id(int new_id)
        {
            *m_Id = new_id;
        }
};


int main()
{
    xboxController x1(90221);
    x1.get_Id();

    // let's copy
    xboxController x2 = x1;
    x2.get_Id();

    // let's change the value
    x1.set_Id(40211);

    // let's check what happened
    x1.get_Id();
    x2.get_Id();

}
Ouput:

90221
90221
40211
40211

But why?
What default class does while copying is similar to what you see below. It invokes this constructor.

xboxController(const xboxController& other)
	: m_Id(other.m_Id)
     {}

This caused the trouble, the pointer is basically copied instead of creating a new memory.
What we can do is define our own copy constructor so we can controll all the stuff while copying.

xboxController(const xboxController& other)
{
    // New memory location is allocated
    m_Id = new int(*(other.m_Id));
}

Private constructors

Constructor is automatically called when the object is created. If it is private then obviously there is error. So how can we access the private constructor.

  1. Using Friends class

    #include <iostream> 
    using namespace std; 
    
    // class A 
    class A{ 
    private: 
        A(){ 
           cout << "constructor of A\n"; 
        } 
    
        // Please note;
        friend class B; 
    }; 
    
    // class B, friend of class A 
    class B{ 
    public: 
        B(){ 
    	// private fn of A can be accessed inside B
    	A a1; 
    	cout << "constructor of B\n"; 
        } 
    }; 
  2. 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.

  3. Named Idiom : Not much that interesting so I copied exactly from GFG

		// 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(); 
	}; 

	// 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; 
	} 

Private Destructors

Why ?

Whenever we want to control destruction of objects of a class, we make the destructor private. For dynamically created objects, it may happen that you pass a pointer to the object to a function and the function deletes the object. If the object is referred after the function call, the reference will become dangling.
Dangling -> pointing to already deleted location.

// CPP program to illustrate 
// Private Destructor 

#include <iostream> 
using namespace std; 

class Test { 
private: 
	~Test() {} 
}; 

Then how to use the class

Test t; 

The compiler notices that the local variable ‘t’ cannot be destructed because the destructor is private.

A.cpp: In function ‘int main()’:
A.cpp:11:10: error: ‘Test::~Test()’ is private within this context
   11 |     Test t1;
      |          ^~
A.cpp:4:9: note: declared private here
    4 |         ~Test() {}
      |   

Then how can we use it ?

Test* t = new Test; 

Now the user is responsible for deleting the object, but how could you ? delete t will call the destructor, it is private, so error.
Then how ? we have to use a friend function for help.

// CPP program to illustrate 
// Private Destructor 
#include <iostream> 

// A class with private destuctor 
class Test { 
private: 
	~Test() {} 
	friend void destructTest(Test*); 
}; 

// Only this function can destruct objects of Test 
void destructTest(Test* ptr) 
{ 
	delete ptr; 
} 

int main() 
{ 
	// create an object 
	Test* ptr = new Test; 

	// destruct the object 
	destructTest(ptr); 

	return 0; 
} 

Virtual Destructor

We need vitual functions when the base and derived class have same function declaration. What about Destructor. When object get deleted, which destructor get called ? As you might suspect it calls the base destructor. So the data allocated for the derived class still exist causing memory leak.

class Base
{
	public:
		Base() {}
		~Base() {}
};

class Derived : public Base
{
	public: 
		Derived() {}
		~Derived() {}
};

int main()
{
	Derived* d1 = new Derived;
	Base* b1 = d1;
	delete b1;    // Here the destructor of base class is called
}

Solution is virtual function

	// in base class
	virtual ~Base() {} 
	// thats it folks we have avoided a nuclear explosion. Fwee!!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment