Copy Constructor in C++

 


A Copy Constructor in C++ is a special constructor that initializes a new object by copying the values from an existing object. It helps in creating exact duplicates of objects.


1️⃣ Characteristics of a Copy Constructor

✅ It copies the values of an existing object to a new object.
✅ It takes a reference to an object of the same class as an argument.
✅ If no copy constructor is defined, C++ provides a default copy constructor.
✅ Used when passing objects by value, returning objects from functions, or initializing objects.


2️⃣ Syntax of Copy Constructor

  • ClassName(const ClassName &oldObject);


  • const ensures the original object remains unchanged.

  • &oldObject avoids infinite recursion by passing a reference.


3️⃣ Example: Default Copy Constructor

If no copy constructor is explicitly defined, C++ automatically provides a default copy constructor.

  • #include <iostream>

  • using namespace std;


  • class Car {

  • public:

  •     string brand;

  •     int year;


  •     // Parameterized Constructor

  •     Car(string b, int y) {

  •         brand = b;

  •         year = y;

  •     }

  • };


  • int main() {

  •     Car car1("Toyota", 2022);  // Parameterized constructor

  •     Car car2 = car1;  // Default Copy Constructor is called


  •     cout << "Car 1: " << car1.brand << ", " << car1.year << endl;

  •     cout << "Car 2: " << car2.brand << ", " << car2.year << endl;


  •     return 0;

  • }


Output:

  • Car 1: Toyota, 2022

  • Car 2: Toyota, 2022


Explanation:

  • Car car2 = car1; copies the brand and year from car1 to car2.

  • Since we didn't define a copy constructor, C++ provides a default one.


4️⃣ Example: User-Defined Copy Constructor

To manually define a copy constructor, we use pass-by-reference.

  • #include <iostream>

  • using namespace std;


  • class Car {

  • public:

  •     string brand;

  •     int year;


  •     // Parameterized Constructor

  •     Car(string b, int y) {

  •         brand = b;

  •         year = y;

  •     }


  •     // Copy Constructor

  •     Car(const Car &obj) {

  •         brand = obj.brand;

  •         year = obj.year;

  •         cout << "Copy Constructor Called!" << endl;

  •     }


  •     void display() {

  •         cout << "Car Brand: " << brand << ", Year: " << year << endl;

  •     }

  • };


  • int main() {

  •     Car car1("Honda", 2023);

  •     Car car2 = car1;  // Calls the Copy Constructor


  •     car1.display();

  •     car2.display();

  •     

  •     return 0;

  • }


Output:

  • Copy Constructor Called!

  • Car Brand: Honda, Year: 2023

  • Car Brand: Honda, Year: 2023


Explanation:

  • Car car2 = car1; invokes the user-defined copy constructor.

  • The copy constructor copies brand and year from car1 to car2.


5️⃣ Copy Constructor with Dynamic Memory Allocation

A shallow copy (default copy constructor) only copies memory addresses, while a deep copy duplicates actual data.

Shallow Copy (Problem with Default Copy Constructor)

  • #include <iostream>

  • using namespace std;


  • class Student {

  • public:

  •     string *name;


  •     // Constructor

  •     Student(string n) {

  •         name = new string(n);  // Allocating memory

  •     }


  •     // Destructor

  •     ~Student() {

  •         delete name;

  •     }

  • };


  • int main() {

  •     Student s1("Alice");

  •     Student s2 = s1;  // Default Copy Constructor


  •     cout << "Student 1: " << *s1.name << endl;

  •     cout << "Student 2: " << *s2.name << endl;


  •     return 0;

  • }


Problem:

  • s2 shares the same memory as s1.

  • When s1 or s2 is destroyed, the same memory is freed twice, leading to undefined behavior.


6️⃣ Solution: Deep Copy Constructor

A deep copy ensures each object gets its own separate memory.

  • #include <iostream>

  • using namespace std;


  • class Student {

  • public:

  •     string *name;


  •     // Constructor

  •     Student(string n) {

  •         name = new string(n);

  •     }


  •     // Deep Copy Constructor

  •     Student(const Student &obj) {

  •         name = new string(*obj.name);  // Allocating new memory

  •         cout << "Deep Copy Constructor Called!" << endl;

  •     }


  •     // Destructor

  •     ~Student() {

  •         delete name;

  •     }


  •     void display() {

  •         cout << "Name: " << *name << endl;

  •     }

  • };


  • int main() {

  •     Student s1("Alice");

  •     Student s2 = s1;  // Calls Deep Copy Constructor


  •     s1.display();

  •     s2.display();


  •     return 0;

  • }


Output:

  • Deep Copy Constructor Called!

  • Name: Alice

  • Name: Alice


Explanation:

  • Instead of copying the memory address, a new memory block is allocated for s2.name.

  • This prevents memory corruption when s1 or s2 is deleted.


7️⃣ When is the Copy Constructor Called?

Scenario

Example

Object Initialization

Car car2 = car1;

Passing an Object by Value

void show(Car c) {}

Returning an Object from a Function

Car func() { return car1; }


8️⃣ Summary

Feature

Default Copy Constructor

User-Defined Copy Constructor

Copies values?

✅ Yes

✅ Yes

Works with dynamic memory?

❌ No (shallow copy)

✅ Yes (deep copy)

Used for object cloning?

✅ Yes

✅ Yes

Example Usage

Car c2 = c1;

Car(const Car &obj) {...}


9️⃣ When to Use a Copy Constructor?

✅ When you pass objects by value.
✅ When returning objects from functions.
✅ When using dynamic memory allocation (to prevent shallow copies).

Would you like to learn about Destructors next? 🚀


Post a Comment

0 Comments