| 語境 | 關鍵字位置 | 核心作用 |
|---|---|---|
| C 風格(程序式) | 全域/區域變數、函數前 | 控制連結屬性(內部連結)與儲存期(靜態儲存期) |
| C++ 類別成員 | 類別內成員宣告前 | 表示屬於類別而非物件,共享單一實體 |
// File1.cpp
static int g_count = 0; // 內部連結,僅本編譯單元可見
int g_global = 0; // 外部連結,其他檔案可 extern 存取
特性:
.cpp 無法 extern 存取,避免命名衝突
void Counter() {
static int count = 0; // 僅初始化一次,保持值至下次呼叫
printf("%d\n", ++count);
}
特性:
static void Helper() { ... } // 內部連結,僅本檔案可呼叫
同靜態全域變數:隱藏實作細節,防止連結器符號衝突,是「檔案級封裝」的關鍵手段。
class Account {
static double interestRate; // 宣告(非定義)
double balance;
public:
static void SetRate(double r) { interestRate = r; }
double GetInterest() const { return balance * interestRate; }
};
double Account::interestRate = 0.03; // 定義於單一 .cpp(全域命名空間)
核心規則:
inline static)Account::interestRate 或 obj.interestRatepublic/protected/private 控制Account::SetRate(0.05))優於全域變數處:不汙染全域命名空間;可私有化實現資訊隱藏。
class Math {
public:
static int Add(int a, int b) { return a + b; } // 無 this 指標
static int GetCallCount() { return s_calls; }
private:
static int s_calls;
};
int Math::s_calls = 0;
特性:
this 指標,不可存取非靜態成員Math::Add(1,2) 或 obj.Add(1,2)(不推薦後者)this 傳遞),但差異可忽略inline static (C++17)
class Widget {
inline static int s_count = 0; // 定義即在類別內,無需 .cpp 定義
};
解決「靜態資料成員必須在 .cpp 定義」的舊痛點,適用於僅頭文件的庫。
Singleton& GetInstance() {
static Singleton instance; // C++11 保證多執行緒首次進入時原子初始化
return instance;
}
實現「Meyers Singleton」的標準寫法。
static_assert (C++11)
static_assert(sizeof(int) == 4, "int must be 4 bytes");
template
void Func() { static_assert(std::is_pod_v, "T must be POD"); }
編譯期斷言,屬 static 關鍵字延伸用法。
| 誤區 | 正確認知 |
|---|---|
| 「static 變數不佔記憶體」 | 佔用全域資料區,程式全期存在 |
| 「類別靜態成員每個物件一份」 | 全類別僅一份,所有物件共享 |
| 「靜態函數不能存取靜態變數」 | 可存取靜態資料成員,不可存取非靜態成員 |
| 「static 等於全域」 | static 限制連結可見性,全域預設外部連結 |
static:內部連結(隱藏符號)+ 靜態儲存期(全域生命週期),是 C/C++ 模組化封裝基石static:靜態儲存期 + 區域作用域,實現狀態保持與延遲初始化static 成員:屬於類別而非物件,共享單一實體,靜態函數無 thisinline static 簡化定義,區域靜態執行緒安全初始化支援 Singleton掌握 static 在不同語境下的精確語義,是寫出正確、可維護、高效能 C++ 代碼的基本功。