ใน C++ const Member Variable ต้องถูก Initialize (กำหนดค่าเริ่มต้น) ครั้งเดียวเท่านั้น และต้องทำใน Member Initializer List** ของ Constructor ไม่สามารถ Assign ได้ภายใน Body ของ Constructor
Syntax
class ClassName {
const Type memberName;
public:
ClassName(ParamType param) : memberName(param) { // Initializer List
// Body: ไม่สามารถ assign memberName ได้แล้ว
}
};
ตัวอย่างสมบูรณ์
#include <iostream>
#include <string>
class Config {
const int maxConnections;
const std::string serverName;
const double timeout;
public:
// Initializer List: เรียงตามลำดับ Declaration ใน Class (ไม่ใช่ลำดับใน List)
Config(int maxConn, std::string name, double t)
: maxConnections(maxConn),
serverName(std::move(name)), // Move Semantics (C++11)
timeout(t)
{
// Body: ใช้สำหรับ Logic อื่นๆ เท่านั้น
std::cout << "Config created for " << serverName << '\n';
}
void print() const {
std::cout << "Max Conn: " << maxConnections
<< ", Server: " << serverName
<< ", Timeout: " << timeout << '\n';
}
};
int main() {
Config cfg(100, "Production-Server", 30.5);
cfg.print();
// Output:
// Config created for Production-Server
// Max Conn: 100, Server: Production-Server, Timeout: 30.5
}
กรณีที่บังคับต้องใช้ Initializer List
| กรณี | เหตุผล |
|---|---|
| const Member | ไม่สามารถ Assign ได้หลัง Construction |
| Reference Member | ต้อง Bind ตั้งแต่สร้าง (int& ref) |
| Base Class Constructor ที่มี Parameter | ต้องส่ง Argument ให้ Base |
| Member Class ที่ไม่มี Default Constructor | ต้องส่ง Argument ให้ Member Constructor |
ลำดับการ Initialize
Member ถูก Initialize ตามลำดับที่ประกาศใน Class Definition ไม่ใช่ลำดับใน Initializer List (Compiler จะ Warn หากลำดับไม่ตรง)
class Foo {
int a;
int b;
public:
Foo() : b(10), a(b + 5) { } // Warning: 'a' initialized before 'b'!
// a ใช้ค่า b ก่อน b ถูก Initialize -> Undefined Behavior
};
C++11 In-Class Member Initialization (Alternative)
สำหรับ Default Values สามารถ Initialize ได้ที่ Declaration:
class Settings {
const int defaultPort = 8080; // C++11
const std::string defaultHost = "localhost";
public:
Settings() = default; // ใช้ Default Values
Settings(int port) : defaultPort(port) {} // Override ได้ใน Initializer List
};
Best Practices
- ใช้ Initializer List เสมอ สำหรับ Members ทั้งหมด (Performance: หลีกเลี่ยง Default Construct + Assign)
- เรียงลำดับใน List ให้ตรงกับ Declaration Order
- ใช้
std::moveสำหรับ Parameter ที่เป็น Rvalue/Expensive-to-copy - Mark Constructor
explicitหาก Single Parameter (ป้องกัน Implicit Conversion)
สรุป
Member Initializer List เป็นกลไกพื้นฐานของ C++ สำหรับ Initialize Members อย่างถูกต้องและมีประสิทธิภาพ const และ Reference Members บังคับให้ใช้ Initializer List เท่านั้น การเข้าใจลำดับการ Initialize และ In-Class Initialization (C++11) ช่วยเขียน Constructor ที่ปลอดภัยและสะอาด