定义

static是C++中关于存储类型的说明符,用static说明的变量称为静态变量。它被用来控制变量的存储方式和可见性。

什么情况下使用静态变量

在函数内部定义的变量,当程序执行到它的定义处时,编译器为它在栈上分配空间,函数在栈上分配的空间在此函数执行结束时会释放掉,这样就产生了一个问题: 如果想将函数中此变量的值保存至下一次调用时,如何实现? 最容易想到的方法是定义为全局的变量,但定义一个全局变量有许多缺点,最明显的缺点是破坏了此变量的访问范围(使得在此函数中定义的变量,不仅仅只受此函数控制)。static关键字则可以很好的解决这个问题。
另外,在 C++ 中,需要一个数据对象为整个类而非某个对象服务,同时又力求不破坏类的封装性,即要求此成员隐藏在类的内部,对外不可见时,可将其定义为静态数据。

静态变量的特点

  • 静态变量军存储在全局数据区,如果程序未显示地给出初始化值,则等效初始化为全0.
  • 静态变量占有的空间要到整个程序执行结束时才释放,因此静态变量具有全局生命期。
  • 静态类成员是由static修饰的类成员,为其所有对象共享,不管有多少对象,静态成员只有一个存在于公共内存中

几种使用方式

全局静态变量

全局可访问,在内存中只有一份拷贝,可被很多函数修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>

static int i = 1; //作用域是整个file

void get(){
std::cout << "in func , the i is " << i << std::endl;
}

int main(){
std::cout << "the i is " << i << std::endl;
get();
return 0;
}

局部静态变量

只能在这个函数中才能被调用。
函数调用结束后,一般局部变量都被回收了,静态变量还存在

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>

void get(){
static int i = 1;
std::cout << "the i is " << i << std::endl;
i++;
}

int main(){
get(); // i = 1
get(); // i = 2
//std::cout << "the i is " << i << std::endl; // 这种是错误的
return 0;
}

全局静态函数

其实跟一般的函数差不多,但是它将该函数的链接属性限制为内链接,只能在本编译单元中使用(也就是本文件),不能被extern等在外部文件中引用。

1
2
3
4
5
6
7
8
9
10
static void get(){
std::cout << "this is staic global func" << std::endl;
}

int main(){
get();
get();
return 0;
}

静态数据成员

格式: 类名::静态数据成员名
需要注意,给静态数据成员初始化必须在类外面。

原理跟函数中的静态变量类似,类实例化出来的对象被销毁后,类变量(静态成员变量)还是存在在内存中的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>

class Widget{
public:
Widget(int i){
a = i;
}
void get();
private:
static int a; // 声明静态变量
};

int Widget::a = 1; // 由于是类变量不是属于专属于一个对象的,被所有对象共享
// 所以需要在类外定义
void Widget::get(){
std::cout << "the a is " << a++ << std::endl;
}

int main(){
Widget w(1);
w.get(); // a = 1
w.get(); // a = 2
return 0;
}

静态函数成员

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>

class Widget{
public:
Widget(int i){
a = i;
}
static void get(); // 声明静态函数

private:
static int a;
int b;
};

int Widget::a = 1;
void Widget::get(){
std::cout << b << std::endl; //这是错误的,因为静态函数和静态变量直接能够
// Widget::get()调用,不需要实例化,所以不能
// 调用只能实例化才能初始化的成员变量。
std::cout << a << std::endl; //ok
}

int main(){

Widget w(1);
w.get();
return 0;
}

参考:

  1. https://www.runoob.com/w3cnote/cpp-static-usage.html
  2. https://www.cnblogs.com/33debug/p/7223869.html