C++ 中的 static 关键字:类成员、局部变量与单例模式
在前面我们聊过 C++ 的函数、引用、类与结构体。这次我们来看看一个常常让初学者迷惑的关键字:static
。
它的作用主要有三类:
类/结构体中的静态成员(全体实例共享)
局部静态变量(作用域局部,生命周期全局)
单例模式(利用静态变量确保唯一实例)
1. 类/结构体中的静态成员
先看一个例子:
#include <iostream>struct Entity
{int x, y;void Print() {std::cout << x << ", " << y << std::endl;}
};int main()
{Entity e;e.x = 2;e.y = 3;Entity e1 = {5, 8};e.Print(); // 2, 3e1.Print(); // 5, 8
}
这时 e
和 e1
各自有独立的 x
和 y
。
如果我们把它们改成静态的:
struct Entity
{static int x, y;
};
编译时会报错:
error LNK2001: 无法解析的外部符号 "public: static int Entity::x"
这是因为 静态成员变量需要在类外部进行定义,否则编译器不知道为它们分配存储空间:
int Entity::x;
int Entity::y;
这样就能正常使用了。
静态成员的特性
静态成员变量在 所有实例中只有一份拷贝。
无论通过哪个对象修改它,所有对象看到的都是同一个值。
使用时推荐直接写
Entity::x
,而不是e.x
,因为它本质上不属于某个实例。
Entity e;
Entity::x = 2;
Entity::y = 3;Entity e1;
Entity::x = 5;
Entity::y = 8;std::cout << Entity::x << ", " << Entity::y; // 输出 5, 8
这就像 Entity
类是一个“命名空间”,x
和 y
属于它本身,而不是对象。
静态方法
静态方法也是类似的:
struct Entity
{static void Print() {std::cout << "Hello Entity" << std::endl;}
};
调用时不需要实例:
Entity::Print();
注意:静态方法不能访问非静态成员,因为它没有绑定到某个对象。
2. 局部 static 变量
static
不仅能用在类里,也能用在函数里:
void Function()
{static int i = 0;i++;std::cout << i << std::endl;
}
和普通局部变量的区别在于:
普通局部变量:每次进入函数都会重新创建,退出函数就销毁。
静态局部变量:只会在第一次调用函数时初始化一次,之后一直存在,直到程序结束。
运行:
for (int j = 0; j < 5; j++)Function();
输出:
1 2 3 4 5
这说明 i
在函数多次调用之间是共享的。
作用域与生命周期
作用域:只在函数内可见。
生命周期:整个程序。
这让它既能避免全局变量的污染,又能保持状态。
3. 单例模式(Singleton)
单例模式指的是 一个类在整个程序中只能有一个实例。
在 C++ 中可以用 static
很方便地实现。
单例模式(Singleton)详解
为什么需要单例?
假设你要做一个游戏引擎,里面有个日志系统 Log
。
你希望:
全局只有一个日志对象
任何地方都能访问它
不想每次用日志都要 new 一个对象
如果每次都写:
Log log1;
Log log2;
就可能有多个实例,日志配置不一致,管理起来很乱。
这时就希望**“某个类在全局只有一个实例”** —— 这就是单例模式。
单例模式的核心思想:
自己管住自己,不让别人随便创建对象,只暴露一个获取实例的方法。
构造函数设为私有(private) → 别人不能随便 new
类里放一个 static 实例 → 全局只有一份
提供一个静态方法 Get() → 外部只能通过它来拿到这个实例
写法 1:类静态指针
#include <iostream>class Singleton
{
private:// 1. 构造函数私有化Singleton() {}// 2. 静态指针,存放唯一实例static Singleton* s_Instance;public:// 3. 静态方法,外部通过它获取实例static Singleton& Get(){if (s_Instance == nullptr)s_Instance = new Singleton(); // 第一次用时才创建return *s_Instance;}void Hello(){std::cout << "Hello from Singleton!" << std::endl;}
};// 类外初始化静态成员
Singleton* Singleton::s_Instance = nullptr;int main()
{// 获取唯一实例Singleton& s1 = Singleton::Get();Singleton& s2 = Singleton::Get();s1.Hello();s2.Hello();std::cout << &s1 << std::endl;std::cout << &s2 << std::endl; // 地址一样 → 确实只有一个对象
}
调用:
Singleton::Get().Hello();//运行结果
Hello from Singleton!
Hello from Singleton!
0x600003e00
0x600003e00
写法 2:局部静态变量(推荐)
class Singleton
{
public:static Singleton& Get(){static Singleton instance; // 第一次调用时创建,以后一直用这一个return instance;}void Hello(){std::cout << "Hello from Singleton!" << std::endl;}private:Singleton() {} // 构造函数私有化
};
调用:
Singleton::Get().Hello();//运行结果
Hello from Singleton!
Hello from Singleton!
0x600003e00
0x600003e00
特点:
只会创建一次(第一次调用时)
线程安全(C++11 起保证了 static 局部变量初始化是线程安全的)
自动销毁(程序结束时,编译器会释放它)