Static Data Member ใน C++ Class เป็นสมาชิกที่ร่วมกันใช้ระหว่างทุก Instance (Object) ของ Class นั้น ต้อง Define และ Initialize นอกจาก Class Definition (Definition) เพราะ Class Definition เป็นแค่ Declaration
Syntax และกฎ
class MyClass {
static int count; // Declaration (ใน Class)
static const int MAX = 100; // const integral: Initialize ใน Class ได้ (C++11)
};
// Definition + Initialization (ใน Global Scope, นอก Class) - จำเป็นสำหรับ Non-const Static
int MyClass::count = 0; // :: Scope Resolution Operator
ตัวอย่างสมบูรณ์: นับจำนวน Object
#include <iostream>
class MyClass {
private:
static int objectCount; // Declaration
public:
MyClass() {
++objectCount;
std::cout << "Object created. Count: " << objectCount << '\n';
}
~MyClass() {
--objectCount;
std::cout << "Object destroyed. Count: " << objectCount << '\n';
}
static int getCount() { return objectCount; }
};
// Definition & Initialization (ต้องอยู่ใน .cpp file ถ้าเป็น Multi-file Project)
int MyClass::objectCount = 0;
int main() {
std::cout << "Initial: " << MyClass::getCount() << '\n'; // 0
MyClass obj1; // 1
MyClass obj2; // 2
{
MyClass obj3; // 3
} // obj3 destroyed -> 2
std::cout << "Final: " << MyClass::getCount() << '\n'; // 2
}
Static Const Members: Special Rules
| Type | Initialize ใน Class? | Definition นอก Class? |
|---|---|---|
static const int / enum | ✅ ได้ (C++11: Integral Constant Expression) | ❌ ไม่ต้อง (ถ้าไม่取 Address) |
static const double / string / Class | ❌ ไม่ได้ (Pre-C++17) | ✅ ต้อง Define นอก Class |
static constexpr (C++11) | ✅ ได้ (ทุก Literal Type) | ❌ ไม่ต้อง (Implicit Inline) |
static inline (C++17) | ✅ ได้ (ทุก Type) | ❌ ไม่ต้อง (Inline Variable) |
C++17 Inline Variables (Modern Way)
class ModernClass {
public:
// Header-only Definition + Initialization (C++17)
static inline int count = 0; // Non-const
static inline const double PI = 3.14159; // Const
static inline std::string name = "Default"; // Complex Type
};
// ไม่ต้อง Define ใน .cpp อีกต่อไป!
การเข้าถึง
- ผ่าน Class:
MyClass::staticMember(Preferred) - ผ่าน Object:
obj.staticMember(ทำงานได้แต่ไม่แนะนำ - 混淆)
ข้อระวัง
- Static Member มีเพียง หนึ่ง Instance ต่อ Program (Shared Across All Objects)
- Initialization Order Across Translation Units: Undefined (Static Initialization Order Fiasco) - ใช้ Function-local Static (Meyers Singleton) แทน
- Thread Safety: Initialization ของ Function-local Static เป็น Thread-Safe (C++11) แต่ Class Static ไม่รับประกัน
สรุป
Static Data Member ต้อง Define/Initialize นอก Class (Pre-C++17) C++17 inline static ทำให้ Header-only Libraries ง่ายขึ้น ใช้ constexpr สำหรับ Compile-time Constants และพิจารณา Thread Safety สำหรับ Complex Initialization