sizeof(Class) 不包含靜態成員)public/protected/private 限制訪問權限| 區域 | 分配時機 | 釋放時機 | 典型例子 |
|---|---|---|---|
| 靜態存儲區 | 編譯/鏈接期(程序啟動前) | 程序結束 | 全局變量、static變量、靜態成員 |
| 棧 | 函數調用時 | 函數返回時 | 局部變量、函數參數、返回地址 |
| 堆 | new/malloc 時 | delete/free 時 | 動態分配對象、數組 |
class A {
static int n; // 聲明:告訴編譯器「A類有一個static int成員」
// 此處不分配內存!
};
// 類外定義:真正分配內存、可選初始化
int A::n = 10; // 定義:分配 4 字節內存,初值 10
static int n; 只是符號聲明,不分配內存int A::n = 10; 才是真正的定義(分配內存+初始化)inline static C++17)// 必須包含類型名(這是初始化而非賦值) int A::n = 10; // 基礎類型 A A::obj; // 類類型(調用默認構造) A A::obj(1, 2); // 類類型(調用帶參構造) const int A::MAX = 100; // const靜態成員(整型可在類內初始化,但建議類外定義)
class A {
public:
inline static int n = 10; // 類內定義+初始化,無需類外定義
inline static const int MAX = 100;
};
class B {
public:
static int n;
static A obj;
};
int B::n = 1;
A B::obj;
int main() {
B b;
// 1. 通過對象訪問
printf("b.n = %d\n", b.n);
printf("b.obj.i = %d\n", b.obj.i);
// 2. 通過類名訪問(推薦,語義更清晰)
printf("B::n = %d\n", B::n);
// printf("B::obj.i = %d\n", B::obj.i); // 若obj非public則不可訪問
}
class B {
private:
static int i;
public:
B() { i = 3; } // 構造函數賦值(運行期)
int get() { return i; }
};
int B::i = 2; // 類外初始化(編譯期)
int main() {
B b;
printf("%d\n", b.get()); // 輸出 3
// 解析:編譯期 i=2 → 運行期構造 b 時 i=3 覆蓋
}
關鍵理解:
不同編譯單元(.cpp)的靜態對象初始化順序未定義:
// File1.cpp static A a; // 構造時依賴 B::data // File2.cpp static B b; // 構造時依賴 A::value
解決方案:使用函數局部靜態變量(Meyers Singleton 模式)保證首次使用時初始化:
A& getA() { static A a; return a; }
B& getB() { static B b; return b; }
class Counter {
private:
inline static int count = 0; // C++17 寫法
public:
Counter() { count++; }
~Counter() { count--; }
static int getCount() { return count; }
};
int main() {
printf("Initial: %d\n", Counter::getCount()); // 0
{
Counter c1, c2;
printf("In block: %d\n", Counter::getCount()); // 2
}
printf("After block: %d\n", Counter::getCount()); // 0
Counter* p = new Counter();
printf("Dynamic: %d\n", Counter::getCount()); // 1
delete p;
return 0;
}
| 維度 | 關鍵點 |
|---|---|
| 內存區域 | 靜態存儲區(全局/靜態區) |
| 生命週期 | 程序啟動 → 程序結束 |
| 初始化時機 | 編譯期/鏈接期(main 前) |
| 定義位置 | 類外(C++17 前)/ 類內 inline static (C++17) |
| 類型要求 | 初始化時必須指明類型 |
| 訪問方式 | 對象. / 類名::(推薦類名) |
| 私有成員 | 類外同樣可初始化 |
| 構造函數 | 運行期執行,可覆蓋初始值 |
| 跨文件順序 | 未定義,用函數局部靜態變量解決 |