一、static 总览
| 使用位置 | 核心作用 | 关键行为 |
|---|---|---|
| 类的静态成员变量 | 类级共享数据 | 所有对象共享一份,类外必须定义 |
| 类的静态成员函数 | 类级工具方法 | 无 this 指针,通过类名调用 |
| 函数内的静态局部变量 | 值持久化 | 只初始化一次,调用间保持值 |
二、类中的静态成员变量
2.1 基本用法
声明 :在类内用 static 声明
定义 :必须在类外用 类型 类名::变量名 = 初值; 分配内存
cpp
class Counter
{
private:
static int count; // 声明:这个变量属于类,不属于任何对象
public:
Counter() { count++; }
~Counter() { count--; }
int GetCount() { return count; } // 所有对象访问的是同一个 count
};
int Counter::count = 0; // 必须定义并初始化!
如果不写类外定义会怎样?
链接时报错:undefined reference to 'Counter::count'。类内只是声明,不分配内存
2.2 内存模型
cpp
Counter a, b, c; // 三个对象
| 成员 | 存储位置 | 份数 |
|---|---|---|
count (static) |
全局数据区 | 1 份,所有对象共享 |
| 其他普通成员 | 每个对象内部 | 每对象 1 份 |
2.3 典型用途
用途 1:对象计数器
cpp
class ECU
{
private:
static int activeInstances;
public:
ECU() { activeInstances++; }
~ECU() { activeInstances--; }
static int GetActiveCount() { return activeInstances; }
};
int ECU::activeInstances = 0;
// 随时查询当前有多少个 ECU 对象存活
write("Active ECUs: %d", ECU::GetActiveCount());
用途 2:全局配置参数
cpp
class AppConfig
{
public:
static int baudRate;
static char logPath[256];
};
int AppConfig::baudRate = 500000;
char AppConfig::logPath[256] = "C:\\logs\\";
// 任何地方直接读写
AppConfig::baudRate = 250000;
用途 3:共享资源句柄
cpp
class Logger
{
private:
static dword fileHandle; // 所有日志对象写入同一个文件
public:
static bool Open(char path[]);
static void Write(char msg[]);
static void Close();
};
dword Logger::fileHandle = 0;
三、类中的静态成员函数
3.1 基本用法
cpp
class MathUtils
{
public:
static float ToFahrenheit(float celsius);
static float ToCelsius(float fahrenheit);
};
float MathUtils::ToFahrenheit(float celsius)
{
return celsius * 9.0 / 5.0 + 32.0;
}
// 调用:直接用类名,无需创建对象
float f = MathUtils::ToFahrenheit(25.0);
3.2 调用方式对比
cpp
MathUtils::ToFahrenheit(25.0); // ✅ 推荐:类名调用
MathUtils util;
util.ToFahrenheit(25.0); // ⚠️ 也能用对象调,但不推荐
3.3 重要限制
静态成员函数没有 this 指针,因此:
| 能做什么 | 不能做什么 |
|---|---|
| ✅ 访问静态成员变量 | ❌ 访问普通成员变量 |
| ✅ 调用其他静态成员函数 | ❌ 调用普通成员函数 |
| ✅ 访问传入的参数 | ❌ 使用 this |
cpp
class Test
{
private:
int normalVal;
static int staticVal;
public:
static void Func()
{
staticVal = 10; // ✅ 可以
// normalVal = 5; // ❌ 错误!没有 this,找不到属于哪个对象
}
};
四、函数内的静态局部变量
4.1 基本用法
在函数内部用 static 声明的变量:只初始化一次,值在函数调用间保留。
cpp
void CountCalls()
{
static int times = 0; // 只在第一次调用时初始化为 0
times++;
write("Called %d times", times);
}
on key 'a'
{
CountCalls(); // 第 1 次:Called 1 times
CountCalls(); // 第 2 次:Called 2 times
CountCalls(); // 第 3 次:Called 3 times
}
4.2 与普通局部变量的对比
cpp
void NormalVar()
{
int n = 0; // 每次调用都重新初始化为 0
n++;
write("Normal: %d", n); // 永远输出 1
}
void StaticVar()
{
static int s = 0; // 只在第一次调用时初始化为 0
s++;
write("Static: %d", s); // 输出 1, 2, 3...
}
| 普通局部变量 | 静态局部变量 |
|-----------|----------|--------|
| 初始化 | 每次调用都初始化 | 只初始化一次 |
| 生命周期 | 函数返回即销毁 | 直到测量结束 |
| 作用域 | 函数内部 | 函数内部 |
| 值在调用间 | 不保留 | 保留 |
4.3 典型用途
用途 1:调用计数器
cpp
void LogError(char msg[])
{
static int errorCount = 0;
errorCount++;
write("Error #%d: %s", errorCount, msg);
}
用途 2:模拟"仅执行一次"的初始化
cpp
void EnsureInitialized()
{
static int done = 0;
if (!done)
{
done = 1;
// 这里的代码只会执行一次
write("System initialized.");
}
}
用途 3:缓存计算结果
cpp
float GetExpensiveValue()
{
static float cachedResult = -1;
static int cached = 0;
if (!cached)
{
cached = 1;
cachedResult = 3.1415926; // 模拟耗时计算
}
return cachedResult;
}
五、三种 static 的对比总结
cpp
class Demo
{
private:
static int shared; // ① 类静态成员变量:所有对象共享
public:
static void Func() // ② 类静态成员函数:无 this,类名调用
{
static int local = 0; // ③ 函数内静态局部变量:值持久
local++;
shared++;
}
};
int Demo::shared = 0; // ① 的类外定义
| 类型 | 声明位置 | 调用/访问方式 | 生命周期 | 共享范围 |
|---|---|---|---|---|
| ① 静态成员变量 | 类内 | 类名::变量名 或 对象.变量名 |
测量期间 | 该类的所有对象 |
| ② 静态成员函数 | 类内 | 类名::函数名() 或 对象.函数名() |
随时可调用 | 无 this,只能访问静态成员 |
| ③ 静态局部变量 | 函数内 | 仅在函数内部 | 测量期间 | 函数的各次调用之间 |