Introduction

Copy Constructor is a type of constructor which is used to create a copy of an already existing object of a class type. It is usually of the form X (X&), where X is the class name. The compiler provides a default Copy Constructor to all the classes. Copy Constructor is of two types:

  1. Default Copy constructor: The compiler defines the default copy constructor. If the user defines no copy constructor, compiler supplies its constructor. Default constructor does only shallow copy.
  2. User Defined constructor: The programmer defines the user-defined constructor. Deep copy is possible only with user defined copy constructor.

 

Copy constructor may be called in following cases:

  • When an object of the class is returned by value.
  • When an object of the class is passed (to a function) by value as an argument.
  • When an object is constructed based on another object of the same class.
  • When the compiler generates a temporary object.

Copy constructor can be made private. When copy constructor is private in a class, objects of that class become non-copyable. This is particularly useful when our class has pointers or dynamically allocated resources.

Shallow Copy Constructor

Shallow copy copies references to original objects. The compiler provides a default copy constructor. Shallow copy constructor is used when class is not dealing with any dynamically allocated memory.

// Shallow Copy constructor example
class ShallowCopyConstructor
{
  char *s_copy;

  public:
  ShallowCopyConstructor(const char *str)
  {
    // Dynamic memory allocation
    s_copy = new char[16]; 
    strcpy(s_copy, str);
  }
  
  // concatenate method
  void concatenate(const char *str)
  {
    // Concatenating two strings
    strcat(s_copy, str); 
  }
  
  ~ShallowCopyConstructor ()
  { 
    delete [] s_copy;
  }
  
  void display()
  {
    cout<<s_copy<<endl;
  }
};

int main()
{
  ShallowCopyConstructor c1("Copy");

  // Copy constructor
  ShallowCopyConstructor c2 = c1;
  
  c1.concatenate("Constructor");

  c1.display();   // OutPut: CopyConstructor
  c2.display();   // OutPut: CopyConstructor
 
  return 0;
}

 

Deep Copy Constructor

Deep copy allocates separate memory for copied information. So the source and copy are different. Any changes made in one memory location will not affect copy in the other location. When we allocate dynamic memory using pointers we need user defined copy constructor. Both objects will point to different memory locations.

// Deep copy constructor
class CopyConstructor
{
  char *s_copy;
  public:
  CopyConstructor (const char *str)
  {
    s_copy = new char[16];
    strcpy(s_copy, str);
  }
  
  // Copy Constructor
  // Syntax is 'Classname(const classname & objectname)'
  CopyConstructor (const CopyConstructor &str)
  {
    s_copy = new char[16];
    strcpy(s_copy, str.s_copy);
  }
  
  void concatenate(const char *str)
  {
    strcat(s_copy, str);
  }

  ~CopyConstructor()
  { 
      delete [] s_copy;
  }

  void display()
  {
      cout<<s_copy<<endl;
  }
};

/* main function */
int main()
{
  CopyConstructor c1("Copy");

  //Invokes copy constructor
  CopyConstructor c2 = c1;

  c1.concatenate("Constructor");
  
  c1.display();   // Shows : CopyConstructor
  c2.display();   // Shows : Copy
  return 0;
}