作用一:修饰局部变量: static 关键字修饰的局部变量,该变量会存放在静态区(全局数据区的一部分),其⽣命周期会⼀直延续到整个程序执行结束。
作用二:修饰全局变量: 对于⼀个全局变量,它既可以在本文件中被访问到,也可以在同⼀个工程中其它源文件被访问(添加 extern进行声明即可)。用 static 对全局变量进行修饰改变了其作用域范围,由原来的整个⼯程可见变成了本文件可见。
举例:

  1. extern int extern_head_global_variable;
  2. extern int extern_static_head_global_variable;
  1. int extern_head_global_variable = 55;
  2. static int extern_static_head_global_variable = 44;

然后在主函数中如下:

  1. int main()
  2. {
  3. printf("extern_head_global_variable = %d\n",
  4. extern_head_global_variable); // output: 55
  5. printf("extern_static_head_global_variable = %d\n",
  6. extern_static_head_global_variable);
  7. }

输出如下: :::info undefined reundefined reference to extern_static_head_global_variable'ference toextern_static_head_global_variable’ ::: 可以看出,源文件中被 static 修饰的全局变量不可被其他文件访问;

作用三:修饰函数:⽤ static 修饰的函数会改变其作用域,即仅能在本源文件中使用。
作用四:修饰类成员变量:如果对类中的成员变量用 static 修饰,则所有类对象共享该静态成员变量。即可以通过类对象访问, 也可以通过类名访问。内存分配时机是在类外部初始化时。
作用五:修饰类成员函数:与静态成员变量相似,如果对类中的成员函数用 static 修饰,则所有类对象共享该静态成员函数。即可以通过类对象访问, 也可以通过类名访问。

(补充:静态非常量数据成员,其只能在类外定义和初始化,在类内仅是声明而已。)


4.0 静态变量的初始化时机?

对于C语言的全局和静态变量:初始化发生在任何代码执行之前,属于编译期初始化。
全局或静态对象:当且仅当对象首次用到时才进行构造。

4.1 追问: 静态成员变量与普通变量的区别是什么?

  • 存储在内存中的位置不同:static 成员变量不占用对象的内存,而是在所有对象之外开辟内存,即使不创建对象也可以访问。具体来说,static 成员变量和普通的 static 变量类似,都在内存分区中的全局数据区分配内存。
  • 内存分配时机不同:static 成员变量的内存既不是在声明类时分配,也不是在创建对象时分配,而是在(类外)初始化时分配。初始化的时候不能再加static。只能在声明的时候加上。
  • 静态成员变量必须初始化,而且只能在类外进行。例如:int Student::m_total = 10; 初始化时若不赋值,那么会被默认初始化为 0。全局数据区的变量都有默认的初始值 0,而动态数据区(堆区、栈区)变量的默认值是不确定的,一般认为是垃圾值。

4.2 追问: 静态成员函数为什么只能访问静态成员?

1> static 成员函数生命周期的特殊性
static成员函数不同于非static函数,它只属于类本身,静态函数随着类的加载而独立存在。与之相反的是非静态成员,他们当且仅当实例化对象之后才存在。也就是说,静态成员函数产生在前,非静态成员函数产生在后,不可能让静态函数去访问一个不存在的东西。

2> static 成员函数没有 this 指针
当调用一个对象的非静态成员函数时,系统会把该对象的起始地址赋给成员函数的this指针。而静态成员函数不属于任何一个对象,因此C++规定静态成员函数没有this指针;
即普通成员函数有 this 指针,可以访问类中的任意成员;而静态成员函数没有 this 指针,只能访问静态成员(包括静态成员变量和静态成员函数)


4.3 追问: 静态成员变量的应用场景?

1> 当各个对象都有相同的某项属性时候。 比如一个存款类, 每个示例其实利息都是相同的。 所以应该把利息设置为存款类的静态数据成员。 这样不管实例化了多少个对象, 利息数据成员共享。


3.4 追问:静态成员函数的应用场景?

实现单例模式?