類別將資料與操作封裝在一起,每個物件擁有獨立的資料成員記憶體空間。但現實場景中,同一類別的多個物件往往需要共享某些資料。例如定義 Person 類別並實例化 person1、person2、person3,若想統計目前存在多少個 Person 物件,就需要一個所有物件共享的計數器。這正是靜態資料成員的用武之地——它屬於類別本身,而非某個具體物件,解決了同類別不同物件間資料與函數共享的問題。
使用 static 關鍵字在類別內部宣告靜態資料成員(如 static int count;),但必須在類別外部進行定義並初始化(如 int Point::count = 0;)。這一步驟缺一不可,否則會發生連結錯誤。初始化必須在實例化任何物件之前完成,因為靜態成員可透過類別名直接存取(Point::count),無需物件存在。
obj.count)或類別名(Class::count)存取,推薦使用類別名以明確語義。既然資料可以共享,操作資料的函數也應該共享。將成員函數宣告為 static,使其成為類別級別的函數。靜態成員函數沒有 this 指標,因此無法直接存取非靜態成員,主要用於操作靜態資料成員。呼叫方式同樣支援物件名與類別名兩種,強烈建議使用 ClassName::staticFunc() 以突顯其類別級別的屬性。
class Point {
public:
Point(int m = 0, int n = 0) : x(m), y(n) { ++count; }
Point(const Point& p) : x(p.x), y(p.y) { ++count; }
~Point() { --count; }
static void ShowCount() { std::cout << count << std::endl; }
private:
int x, y;
static int count; // 宣告
};
int Point::count = 0; // 定義並初始化
// 使用示範
Point A(4, 5);
A.ShowCount(); // 輸出 1(透過物件呼叫)
Point::ShowCount(); // 輸出 1(透過類別呼叫,推薦)
Point B(A);
Point::ShowCount(); // 輸出 2
掌握靜態成員的本質與規則,能讓你在設計需要全域狀態管理、資源計數、單例模式等場景時遊刃有餘,寫出更優雅、高效的 C++ 程式碼。