类中的static
在class之外的static,意味着被修饰的符号在link阶段只在局部有效,它只对定义它的编译单元(.obj)可见。
在class或struct中的static,这意味着这部分内存是这个类中的所有实例所共享的。
举个例子
#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();
e1.Print();
std::cin.get();
}
当运行时,我会获得”2,3“和”5,8“,毫无疑问。
当修改代码,将x
和y
改为静态变量时,编译器直接报错。
为了消除报错,修改代码,并定义静态变量
#include <iostream>
struct Entity
{
static int x, y;
void Print()
{
std::cout << x << "," << y << std::endl;
}
};
int Entity::x;
int Entity::y;
int main()
{
Entity e;
e.x = 2;
e.y = 3;
Entity e1;
e1.x = 5;
e1.y = 8;
e.Print();
e1.Print();
std::cin.get();
}
这时再运行,则会发现打印了两次”5,8“,表明在这两个实例指向的变量处在一个内存空间。
因此上述代码相当于
Entity::x = 5;
Entity::y = 8;
跟直接在类中定义并无区别,从这种意义上说,他们并不真的属于类。
静态方法不能访问非静态变量
值得一提的是,如果将Print()
函数定义为静态,此时用其调用非静态的实例时则会报错。原因是静态方法没有类实例。本质上,在类中写的每个非静态方法都会获得当前的类实例作为参数。从本质上讲,静态方法与在类外定义的函数并无区别,这也是为何在调用非静态参数时会报错,它根本没有获取到实例中的参数。
局部作用域中的static
变量的生命周期与作用域
生命周期,即变量在内存中,被删除前存在的时间。
作用域,即我们能够访问这个变量的范围。比如在函数内部定义的变量就不能被外部访问,因为它是局部的。
静态局部变量(local static)则允许我们声明一个变量,它的生命周期是程序的存在时间,而作用域取决于其所在的位置,如函数内部。
举个例子
#include <iostream>
void Function()
{
int i = 0;
i++;
std::cout << i << std::endl;
}
int main()
{
Function();
Function();
Function();
Function();
Function();
std::cin.get();
}
比如说这段代码,i
在函数内被声明,因此当我连续五次调用Function()
时,控制台上会显示出5次1,但当我把变量类型改为static int
,我则会获得自增的五个数字1~5。
那么问题来了,static int
与在函数外直接声明i
有什么区别呢?
区别在于上面提到的作用域,如果在外部声明了i
,则可在代码的任何位置访问到它,这可能导致程序的运行错误,比如在第一次调用Function()
后将将i
赋值为10,则结果变为1以及11~15。
教程来源:The Cherno C++ 教程