首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++ static 關鍵字全解析:從 C 風格到類別成員的完整語義

     編輯:關於C++

概覽:兩大語境,截然不同的語義

語境關鍵字位置核心作用
C 風格(程序式)全域/區域變數、函數前控制連結屬性(內部連結)與儲存期(靜態儲存期)
C++ 類別成員類別內成員宣告前表示屬於類別而非物件,共享單一實體

一、C 風格 static

1. 靜態全域變數


// File1.cpp
static int g_count = 0;  // 內部連結,僅本編譯單元可見
int g_global = 0;        // 外部連結,其他檔案可 extern 存取

特性:

  • 儲存於全域/靜態資料區,程式啟動時零初始化,結束時銷毀
  • 內部連結:符號不輸出至目標檔,其他 .cpp 無法 extern 存取,避免命名衝突
  • 每個編譯單元可擁有同名靜態全域變數,互不干擾

2. 靜態區域變數


void Counter() {
    static int count = 0;  // 僅初始化一次,保持值至下次呼叫
    printf("%d\n", ++count);
}

特性:

  • 儲存於全域資料區(非堆疊),生命週期 = 程式全期
  • 首次執行到宣告處才初始化(C++11 保證執行緒安全)
  • 作用域仍為區域(僅函數/區塊內可見)
  • 未顯式初始化者自動歸零

3. 靜態函數


static void Helper() { ... }  // 內部連結,僅本檔案可呼叫

同靜態全域變數:隱藏實作細節,防止連結器符號衝突,是「檔案級封裝」的關鍵手段。

二、類別靜態成員

1. 靜態資料成員


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(全域命名空間)

核心規則:

  • 宣告在類別內,定義在類別外(除 C++17 inline static)
  • 僅存在單一實體,全體物件共享
  • 存取方式:Account::interestRate 或 obj.interestRate
  • 受 public/protected/private 控制
  • 無物件時亦可存取(如 Account::SetRate(0.05))

優於全域變數處:不汙染全域命名空間;可私有化實現資訊隱藏。

2. 靜態成員函數


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 傳遞),但差異可忽略

三、進階與現代 C++

inline static (C++17)


class Widget {
    inline static int s_count = 0;  // 定義即在類別內,無需 .cpp 定義
};

解決「靜態資料成員必須在 .cpp 定義」的舊痛點,適用於僅頭文件的庫。

區域靜態變數的執行緒安全初始化 (C++11)


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 成員:屬於類別而非物件,共享單一實體,靜態函數無 this
  • 現代 C++:inline static 簡化定義,區域靜態執行緒安全初始化支援 Singleton

掌握 static 在不同語境下的精確語義,是寫出正確、可維護、高效能 C++ 代碼的基本功。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved