Copy Constructor
In this part you will learn:
1. What is copy constructor?
2. Usage of copy constructor
3. Syntax of Copy Constructor
4. Writing program with copy constructor
5. Showing output
Copy Constructor
A copy constructor is a special constructor that initializes a new object from an existing object. Following are the three occasions when copy constructor is called
• When instantiating one object and initializing it with values from another object.
• When passing an object by value.
• When an object is returned from a function by value.
What if you don’t create a copy constructor? Compiler will create a default copy constructor which copies your class data bit by bit. The bit wise copy is also known as shallow copy, but there is a very bad problem doing shallow copying.
Consider the following example which we used earlier.
Of course you have to add the headers but right now focus on the main part of this program
Program without Copy Constructor
class set
{
public:
int *ele;
int size;
set(){
cout << endl << "Default constructor called" << endl;
size = 0;
ele = NULL;
}
set(int n){
cout << endl << "Overloaded constructor called" << endl;
size = n;
ele = new int [size];
}
~set(){
cout << endl << "Destructor called" << endl;
if (size > 0)
delete[]ele;
ele = NULL;
}
};
The class definition is normal, note that there is no copy constructor in it.
int main()
{
set a(5);
{
set b=a; //calling default copy constructor
}
}
In the main of the program, we see that in the outer brackets an object ‘a’ is created then in curly brackets we initialize an object with an existing object ‘a’. All the data present in object ‘a’ is copied to the object ‘b’ bit by bit. That means that the member variable ‘ele’ of object b will be pointing to the memory being pointed by ‘ele’ of object a.
When the scope of object b will end, i.e when inner curly brackets will end. The destructor will be called for object b and it will delete the memory pointed by ‘ele’ which is exactly the same as the ‘ele’ of object a. Now when the destructor of object a will be called, it will try to delete memory which is already been deleted. At this moment we will face a run time error.
You can check the error in the above code by running it.
So, what is the solution for this problem? Of course we have to go for deep copy, in deep copy we first create an array of the same size then copy the CONTENT of the other object. Note that here is a difference between copying content and just copy address. Deep copy will create a separate memory array for the new born object.
Syntax
Class_Name(const Class_Name & any_Name)
{
//deep copying any_Name into the caller function
}
It is necessary to use & in the parameter if the copy constructor, because if we would not use it, it would start making another copy of copy constructor and that copy will try to make another copy and so on. This will result in an infinite recursion of our copy constructor.
Note: Copy constructor is needed when you want to deep copy data otherwise it is not necessary. Which means you will need a destructor too otherwise not.
Program with Copy Constructor
Continuing from the previous example, as I have pointed out the problem in the code. Now we will execute the same code after adding copy constructor function in it.
Note: In this example I have made the member variable’s access Public for the sake of simplicity because right now we are focusing on copy constructor, as we have discussed earlier, we can make them private and use getters and setters to access them.
Basic Step:
#include<iostream>
#include<conio.h>
using namespace std;
These two are the most common and basic lines of a c++ program. The first one iostream is used to grant us most of the basic functions of C++ like Input and Output functions. The second one conio.h means console input output, the black screen we see is the console. Using namespace std; provides us an ease of using all the library functions without specifying that this function belongs to standard library. Without including it, we have to write ‘std’ with all the built-in functions.
Class
class set
{
public:
int *ele;
int size;
set(){
cout << endl << "Default constructor called" << endl;
size = 0;
ele = NULL;
}
set(int n){
cout << endl << "Overloaded constructor called" << endl;
size = n;
ele = new int [size];
}
~set(){
cout << endl << "Destructor called" << endl;
if (size > 0)
delete[]ele;
ele = NULL;
}
set(const set & obj){ //performing deep copy
size = obj.size;
ele = new int[size]; //creating a seperate array for caller function
for (int i = 0; i < size; i++)
ele[i] = obj.ele[i];
}
};
The above given code is the definition of class “set” which has 2 member variables ele and size. The last function in the above class definition is called the copy constructor function. In this function, we are deep copying the values of object obj into the caller object.
Note: This is an example of only two variables, we can add as many variables as we want and assign values to each member variable using this technique.
Main
int main()
{
set a;
{
set b=a;
}
}
Now the program will work just fine, when the value of object b will be initialized. Copy constructor will be called and it will deep copy the data of object a. When the scope of object b would end. Its destructor will be called and it will not disturb the memory occupied by object a. Later when the program will end there would be no issue while the destruction of object a.
Note: As output we will see “Overloaded Constructor called” a single time but “Destructor called” twice. This is because while initialization of object b, constructor will not be called rather copy constructor will be called.
Output