普通成员变量每个对象都有一份,而静态成员变量所有对象共享同一份——它不属于任何一个对象,而是属于整个类。
班里每个同学都有自己的笔记本——这是普通成员变量,每人一份,互不干扰。
但班级的公告栏只有一块,全班共用,任何一个人写上去,所有人都能看到——这就是静态成员变量。它属于整个班级(类),而不属于某一个同学(对象)。
name、score)每个对象各有一份,存在对象自己的内存里。count)只有一份,存在类的公共区域,所有对象读写的都是同一个值。
在成员变量前加 static 关键字即可。但有一个特别的规定:静态成员变量必须在类外单独定义(初始化),不能只在类内声明就了事。
| 1 | class Student { |
| 2 | public: |
| 3 | string name; |
| 4 | static int count; // 类内声明,注意只是声明 |
| 5 | |
| 6 | Student(string n) : name(n) { |
| 7 | count++; // 每创建一个对象就 +1 |
| 8 | } |
| 9 | ~Student() { count--; } // 每销毁一个对象就 -1 |
| 10 | }; |
| 11 | |
| 12 | int Student::count = 0; // ← 类外定义并初始化,不能省略! |
| 13 | |
| 14 | int main() { |
| 15 | Student s1("Alice"); |
| 16 | Student s2("Bob"); |
| 17 | cout << Student::count; // 输出:2(用 类名:: 访问) |
| 18 | cout << s1.count; // 也可以用对象访问,但不推荐(容易误以为是独立的) |
| 19 | } |
int Student::count = 0;。忘了写,链接时会报"未定义的引用"错误。
成员函数也可以用 static 修饰。静态成员函数和静态变量一样,不依赖任何具体的对象,可以直接通过类名调用,无需创建对象。
正因为如此,静态成员函数里没有 this 指针——它不知道也不关心是哪个对象在调用它,因此它只能访问静态成员,不能访问普通成员变量。
| 1 | class Student { |
| 2 | private: |
| 3 | string name; |
| 4 | static int count; |
| 5 | public: |
| 6 | Student(string n) : name(n) { count++; } |
| 7 | ~Student() { count--; } |
| 8 | |
| 9 | static int GetCount() { // 静态成员函数 |
| 10 | return count; // ✅ 可以访问静态成员 |
| 11 | // return name; ❌ 不能访问普通成员(没有 this) |
| 12 | } |
| 13 | }; |
| 14 | int Student::count = 0; |
| 15 | |
| 16 | int main() { |
| 17 | cout << Student::GetCount(); // 输出:0(不需要创建对象就能调用) |
| 18 | Student s1("Alice"), s2("Bob"); |
| 19 | cout << Student::GetCount(); // 输出:2 |
| 20 | } |
static。最典型的例子:获取对象计数、工厂方法(创建对象的辅助函数)、工具类里的纯计算函数。
| 对比项 | 普通成员 | 静态成员 |
|---|---|---|
| 属于谁 | 每个对象各有一份 | 整个类共享一份 |
| 内存位置 | 对象内部(栈或堆) | 程序的静态存储区 |
| 生命周期 | 随对象创建/销毁 | 程序启动到结束,始终存在 |
| 访问方式 | 对象.成员 |
类名::成员(推荐)或 对象.成员 |
| 能否访问 this | ✅ 有 this 指针 | ❌ 没有 this 指针 |
| 初始化位置 | 构造函数 / 初始化列表 | 类外单独定义(必须) |
静态成员在以下几个场景非常好用:
| 1 | class Game { |
| 2 | public: |
| 3 | static const int MAX_PLAYERS = 4; // const static 可以直接在类内初始化 |
| 4 | static const int MAP_SIZE = 100; |
| 5 | }; |
| 6 | |
| 7 | // 用类名直接访问,清晰地表达"这是 Game 的配置" |
| 8 | int arr[Game::MAP_SIZE]; |
| 1 | class Config { |
| 2 | private: |
| 3 | Config() {} // 构造函数私有,外部无法直接创建 |
| 4 | static Config* instance; |
| 5 | public: |
| 6 | static Config* GetInstance() { |
| 7 | if (!instance) |
| 8 | instance = new Config(); // 第一次调用才创建 |
| 9 | return instance; // 之后返回同一个实例 |
| 10 | } |
| 11 | }; |
| 12 | Config* Config::instance = nullptr; |
static 成员变量:整个类共享一份,生命周期贯穿程序始终,必须在类外定义。static 成员函数:无 this 指针,只能访问静态成员,用 类名:: 直接调用。