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

Constructors ใน C++ (Constructor ทุกประเภท)

Constructor เป็น Member Function พิเศษที่ทำงานเมื่อสร้าง Object ชื่อเดียวกับ Class ไม่มี Return Type ใช้สำหรับ Initialize Object

ประเภทของ Constructor

ประเภท ลายเซ็น คำอธิบาย
Default ConstructorClassName()ไม่มีพารามิเตอร์ (หรือทุกตัวมี default)
Parameterized ConstructorClassName(args...)รับพารามิเตอร์เพื่อ Initialize
Copy ConstructorClassName(const ClassName&)คัดลอกจาก Object เดิม
Move Constructor (C++11)ClassName(ClassName&&)ย้าย Resource จาก Temporary Object
Delegating Constructor (C++11)เรียก Constructor อีกตัวในคลาสเดียวกันลดโค้ดซ้ำ
Converting Constructorรับ 1 พารามิเตอร์ (ไม่ explicit)Implicit Conversion
Explicit Constructorexplicit ClassName(args)ป้องกัน Implicit Conversion

1. Default Constructor

class A {
    int num1, num2;
public:
    A() : num1(5), num2(7) {}  // Initializer List
    void display() { cout << num1 << " " << num2; }
};

int main() {
    A obj;  // เรียก Default Constructor
    obj.display();  // 5 7
}

2. Parameterized Constructor

class A {
    int num1, num2;
public:
    A(int n1, int n2) : num1(n1), num2(n2) {}
    void display() { cout << num1 << " " << num2; }
};

int main() {
    A obj(3, 8);  // เรียก Parameterized Constructor
    obj.display();  // 3 8
    
    // Explicit call
    A obj2 = A(1, 2);
    A obj3 = (1, 2);  // C-style cast (ไม่แนะนำ)
}

3. Constructor Overloading


class Flexible {
    int x, y;
    string name;
public:
    Flexible() : x(0), y(0), name("default") {}
    Flexible(int a) : x(a), y(0), name("one arg") {}
    Flexible(int a, int b) : x(a), y(b), name("two args") {}
    Flexible(int a, int b, string n) : x(a), y(b), name(std::move(n)) {}
    
    void print() { cout << name << ": " << x << ", " << y << endl; }
};

int main() {
    Flexible f1;
    Flexible f2(5);
    Flexible f3(5, 10);
    Flexible f4(1, 2, "custom");
    f1.print(); f2.print(); f3.print(); f4.print();
}

4. Delegating Constructor (C++11)


class Delegating {
    int x, y;
    string name;
public:
    // Target Constructor (หลัก)
    Delegating(int a, int b, string n) : x(a), y(b), name(std::move(n)) {
        cout << "Target constructor" << endl;
    }
    
    // Delegating constructors
    Delegating() : Delegating(0, 0, "default") {}
    Delegating(int a) : Delegating(a, 0, "one arg") {}
    Delegating(int a, int b) : Delegating(a, b, "two args") {}
};

5. Member Initializer List (แนะนำให้ใช้เสมอ)


class Efficient {
    const int id;           // ต้อง init ที่นี่
    string name;            // เรียก string constructor 1 ครั้ง
    vector<int> data;       // เรียก vector constructor 1 ครั้ง
    OtherClass obj;         // เรียก OtherClass constructor
    
public:
    // ✓ ดี - ใช้ Initializer List
    Efficient(int id, string n) : id(id), name(std::move(n)), data(100), obj(id) {}
    
    // ✗ ไม่ดี - Default construct แล้วค่อย Assign
    // Efficient(int id, string n) { 
    //     this->id = id;  // Error: const ไม่ assign ได้
    //     name = n;       // 2 ครั้ง: default + assign
    // }
};

6. Explicit Constructor (ป้องกัน Implicit Conversion)


class ExplicitOnly {
    int value;
public:
    explicit ExplicitOnly(int v) : value(v) {}
};

void func(ExplicitOnly obj) {}

int main() {
    ExplicitOnly obj1(10);     // ✓ Direct initialization
    ExplicitOnly obj2 = 10;    // ✗ Error: implicit conversion
    func(10);                  // ✗ Error: implicit conversion
    func(ExplicitOnly(10));    // ✓ Explicit construction
}

ลำดับการ Initialize

  1. Base Class Constructors (เรียงตามลำดับสืบทอด)
  2. Member Variables (เรียงตามลำดับที่宣告ในคลาส - ไม่ใช่ลำดับใน initializer list!)
  3. Constructor Body

class Order {
    int a, b;
public:
    Order() : b(10), a(b + 5) {}  // ⚠️ a ใช้ b ก่อน b init เสร็จ!
    // Declaration order: a แล้ว b
    // Init list order: b แล้ว a
    // จริงๆ a จะได้ค่า garbage + 5
};

สรุป Best Practices

  • ใช้ Initializer List เสมอ
  • ประกาศ Member เรียงตามลำดับ Dependency
  • ทำ explicit สำหรับ Single-Argument Constructor (ยกเว็นะ Copy/Move)
  • ใช้ = default / = delete แทนการเขียนว่างเปล่า
  • ปฏิบัติตาม Rule of 0/3/5