Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> C++

Copy Constructor ใน C++ (Constructor คัดลอก)

Copy Constructor เป็น Constructor พิเศษที่สร้าง Object ใหม่โดย คัดลอกจาก Object เดิมของคลาสเดียวกัน

ลายเซ็นมาตรฐาน

ClassName(const ClassName& other);

ต้องรับ const reference เพื่อป้องกัน Infinite Recursion (ถ้ารับ by value จะต้อง copy อีกครั้ง)

โค้ดตัวอย่าง

#include <iostream>
using namespace std;

class Demo {
private:
    int num1, num2;
    
public:
    // Normal Constructor
    Demo(int n1, int n2) : num1(n1), num2(n2) {
        cout << "Parameterized Constructor" << endl;
    }
    
    // Copy Constructor
    Demo(const Demo& other) : num1(other.num1), num2(other.num2) {
        cout << "Copy Constructor called" << endl;
    }
    
    void display() const {
        cout << "num1 = " << num1 << ", num2 = " << num2 << endl;
    }
};

int main() {
    Demo obj1(10, 20);      // Parameterized Constructor
    Demo obj2 = obj1;       // Copy Constructor (Copy Initialization)
    Demo obj3(obj1);        // Copy Constructor (Direct Initialization)
    
    obj1.display();
    obj2.display();
    obj3.display();
    
    return 0;
}

ผลลัพธ์

Parameterized Constructor
Copy Constructor called
Copy Constructor called
num1 = 10, num2 = 20
num1 = 10, num2 = 20
num1 = 10, num2 = 20

เมื่อไหร่ Copy Constructor ถูกเรียก?

สถานการณ์ ตัวอย่าง
Copy InitializationType obj2 = obj1;
Direct InitializationType obj2(obj1);
Pass by Value to Functionvoid func(Type obj); func(obj1);
Return by Value from FunctionType func() { return obj; }
Initialize in Containervector<Type> v; v.push_back(obj);

Shallow Copy vs Deep Copy

Shallow Copy (Default)

คัดลอกค่า Member ทุกตัวแบบ Bitwise

class Shallow {
    int* data;
public:
    Shallow(int v) { data = new int(v); }
    // Compiler-generated copy constructor
    // data ชี้ไปที่เดียวกัน!
};

❌ ปัญหา: Double Free, Dangling Pointer

Deep Copy (Manual)

จอง Memory ใหม่ และคัดลอกข้อมูล

class Deep {
    int* data;
public:
    Deep(int v) { data = new int(v); }
    Deep(const Deep& other) {
        data = new int(*other.data);  // Deep copy
    }
    ~Deep() { delete data; }
};

✓ ปลอดภัย: แต่ละ Object มี Memory ของตัวเอง

Default Copy Constructor (Compiler-generated)

  • ทำ Member-wise Shallow Copy
  • เหมาะสำหรับ Class ที่มีแค่ Primitive Types หรือ RAII Types (string, vector, smart pointers)
  • ไม่เหมาะ สำหรับ Raw Pointers, File Handles, Socket Handles

การปิดกั้น Copy (Non-copyable)


class NonCopyable {
public:
    NonCopyable() = default;
    NonCopyable(const NonCopyable&) = delete;           // ห้าม Copy Construct
    NonCopyable& operator=(const NonCopyable&) = delete; // ห้าม Copy Assign
};

// หรือสืบทอดจาก base
class NonCopyableBase {
protected:
    NonCopyableBase() = default;
    ~NonCopyableBase() = default;
    NonCopyableBase(const NonCopyableBase&) = delete;
    NonCopyableBase& operator=(const NonCopyableBase&) = delete;
};

Rule of 3/5/0 (เชื่อมโยงกับ Destructor)

  • ถ้าเขียน Destructor เอง → ควรเขียน Copy Constructor และ Copy Assignment ด้วย (Rule of 3)
  • C++11: เพิ่ม Move Constructor และ Move Assignment (Rule of 5)
  • Modern C++: ใช้ RAII Types → ไม่ต้องเขียนอะไร (Rule of 0)

Copy Elision (Optimization)

Compiler อาจ ข้าม Copy Constructor ได้ (C++17 บังคับบางกรณี)


Demo createDemo() {
    return Demo(10, 20);  // อาจสร้างตรงใน obj3 (NRVO)
}

int main() {
    Demo obj3 = createDemo();  // อาจมีเพียง 1 Constructor call
}