static的使用场景分类
全局静态变量
- 存储位置:在程序的全局数据区,即使定义在函数内部,其生命周期也贯穿整个程序运行期。
- 初始化:只初始化一次,初始化时机在程序启动时进行。
- 作用域:仅限于定义它的文件内部。尽管是全局的,由于static修饰符的存在,它不会与其他文件中的同名全局变量冲突。
- 默认初始值:如果没有显式初始化,全局静态变量会被自动初始化为0(对于基本数据类型)。
函数内部的静态变量
- 存储位置:与全局静态变量相同,存储在程序的全局数据区,不在栈上。
- 初始化:只在第一次调用该函数时初始化一次,之后即使函数退出,该变量的值也不会消失,而是保持上一次调用结束时的值。
- 作用域:仅限于定义它的函数内部,外部无法访问。
- 生命周期:从第一次被初始化开始,直到程序运行结束。
- 默认初始值:如果没有显式初始化,函数内的静态变量也会被自动初始化为0。
理解什么叫只初始化一次:意思是无论这个函数被调用多少次,它只在第一次调用的时候被初始化,往后不会被初始化,举个例子:
void counter() {
static int count = 0; // 静态变量初始化
count++;
std::cout << "Current count is " << count << std::endl;
}
int main() {
for (int i = 0; i < 5; ++i) {
counter(); // 每次调用都会增加count,但初始化只在第一次调用时发生
}
return 0;
}
输出结果如下,可以看到每次的输出结果并不会被重新覆盖,这就是所谓的只初始化一次,生命周期延长至整个程序:
Current count is 1
Current count is 2
Current count is 3
Current count is 4
Current count is 5
静态成员变量
- 所有对象共享一个变量,有一个对象进行修改,其它对象拥有的值就会发生变化
- 编译阶段分配内存
- 类内声明类外初始化
- 可通过类直接访问
- 存储在全局数据区
静态成员函数
- 存储在代码区
- 所有对象共享一个函数
- 静态成员函数只能访问静态成员变量,因为它们都是专属于类的
- 静态成员函数没有this指针
引申:C++内存分区,栈区、堆区、全局/静态存储区、常量存储区,代码区
项目中遇到的使用情况
总结一下目前做项目时,通常需要在什么地方加static,目前来说遇到的情况通常是在头文件中定义的时候
取代宏
宏是不安全的,而且会导致代码可读性变差,通常我们用static const来替代define,比如:
#define Pi 3.14;
static const int Pi = 3.14;
类中定义静态成员函数
这个一般分两种情况,主要是链接性问题还有就是管理问题
链接性
在写C++的时候,通常都是把类的定义放在头文件里的,有的函数对于类来说是执行特定操作的工具函数,但是头文件很容易被包含来包含去,为了防止链接出错,我们定义它们为static,比如:
static void*& ObjNext(void* obj) {
return *(void**)obj;
}
这个函数中获取了一个内存块前指针大小个字节中存储的地址,为了预防多个cpp文件使用时链接出错,把它定义为static属性
需要注意的一点是:头文件中定义的static所修饰的普通变量、普通函数、类中的静态成员变量,包含这个头文件的源文件中只有其副本,不同源文件之间互不影响,静态成员函数专属于类,它不受链接性的影响
管理问题
考虑这样一种情况,我们需要定义一组关联性较强的函数来执行某个功能,如果把这些函数全都暴露在外面就会显得乱糟糟的,因此我们把他们放到一个类里面去管理,但如果定义成普通成员函数,使用的时候就必须先实例化一个对象,然后通过对象调用这些成员函数。但是如果都设置为静态函数,就可以直接通过类名来调用,要方便很多。
举个简单的例子理解一下:
//caculate.h
class caculate
{
static int add(int x, int y);
static int add(int x, int y);
};
//test.cpp直接用类名来调用
caculate::add(3,5);
caculate::sub(6,4);