Qingquan-Li / blog

My Blog
https://Qingquan-Li.github.io/blog/
132 stars 16 forks source link

C++ Copy Constructors #250

Open Qingquan-Li opened 1 year ago

Qingquan-Li commented 1 year ago

Concept: A copy constructor is a special constructor that is called whenever a new object is created and initialized with another object's data.

A copy constructor is called when:

1. Copy Constructor Example

A copy constructor is a member function that initializes an object using another object of the same class. It is used to perform a deep copy or sometimes a shallow copy of objects.

class SimpleClass {
private:
    int num;

public:
    // Default constructor
    // SimpleClass() : num(0) {} // explicitly initialize num to 0
    SimpleClass() {}

    // Parameterized constructor
    SimpleClass(int n) {
        num = n;
    }

    // Copy constructor
    // `const`: cannot modify the object obj inside the copy constructor.
    // `&`: pass by reference rather than by value (make a copy).
    //      If pass it by value, cannot access the original object's private members.
    SimpleClass(const SimpleClass &obj) {
        num = obj.num;
    }

    void showNum() const {
        std::cout << "Number: " << num << std::endl;
    }
};

2. Deep Copy vs Shallow Copy

Since the default copy constructor is essentially a shallow copy (copy the address of the object). We need to define a copy constructor with objects containing dynamic memory.

// Deep Copy with Dynamic Memory Allocation

class DeepCopyClass {
private:
    int *numPtr;

public:
    // Default constructor
    DeepCopyClass() {
        numPtr = new int;
        *numPtr = 0;
    }

    // Parameterized constructor
    DeepCopyClass(int n) {
        numPtr = new int;
        *numPtr = n;
    }

    // Copy constructor for deep copy
    // deep copy: copy the value of the object, not the address
    // shallow copy: copy the address of the object
    DeepCopyClass(const DeepCopyClass &obj) {
        numPtr = new int; // allocate memory for the new object
        *numPtr = *(obj.numPtr); // copy the value of the object
    }

    ~DeepCopyClass() {
        delete numPtr;
    }

    void showNum() const {
        std::cout << "Number: " << *numPtr << std::endl;
    }
};
// Shallow Copy (not recommended for dynamic memory)

class ShallowCopyClass {
private:
    int *numPtr;

public:
    // Default constructor
    ShallowCopyClass() {
        numPtr = new int;
        *numPtr = 0;
    }

    // Parameterized constructor
    ShallowCopyClass(int n) {
        numPtr = new int;
        *numPtr = n;
    }

    // Copy constructor for shallow copy
    ShallowCopyClass(const ShallowCopyClass &obj) {
        numPtr = obj.numPtr; // copy the address of the object
    }

    ~ShallowCopyClass() {
        delete numPtr;
    }

    void showNum() const {
        std::cout << "Number: " << *numPtr << std::endl;
    }
};