Constructor เป็น Member Function พิเศษที่ทำงานเมื่อสร้าง Object ชื่อเดียวกับ Class ไม่มี Return Type ใช้สำหรับ Initialize Object
ประเภทของ Constructor
| ประเภท | ลายเซ็น | คำอธิบาย |
|---|---|---|
| Default Constructor | ClassName() | ไม่มีพารามิเตอร์ (หรือทุกตัวมี default) |
| Parameterized Constructor | ClassName(args...) | รับพารามิเตอร์เพื่อ Initialize |
| Copy Constructor | ClassName(const ClassName&) | คัดลอกจาก Object เดิม |
| Move Constructor (C++11) | ClassName(ClassName&&) | ย้าย Resource จาก Temporary Object |
| Delegating Constructor (C++11) | เรียก Constructor อีกตัวในคลาสเดียวกัน | ลดโค้ดซ้ำ |
| Converting Constructor | รับ 1 พารามิเตอร์ (ไม่ explicit) | Implicit Conversion |
| Explicit Constructor | explicit 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
- Base Class Constructors (เรียงตามลำดับสืบทอด)
- Member Variables (เรียงตามลำดับที่宣告ในคลาส - ไม่ใช่ลำดับใน initializer list!)
- 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