Static关键字
static关键字在C++中有两个意思,这取决于上下文,其中之一是在类或结构体外使用static关键字,另一种是在类或结构体内使用static。类外部的static静态变量,意味着你声明为static的符号,链接只是在内部,这意味这它只能对你定义它的翻译单元可见。类内部的static静态变量,将与类的所有实例共享内存,这意味着该静态变量在你类中创建的所有实例中只有一个实例。对于static方法而言,这在告诉编译器这个方法只会在当前翻译单元中被用到,其他翻译单元不会调用,这将会影响链接过程。
静态变量或者函数意味着,当需要将这些函数或变量与实际定义的符号链接时,链接器不会在这个翻译单元的作用域之外寻找那个符号的定义。
类与结构体之外的静态
Example 1
1 2 3 4 5 6 7 8 9
| #include <iostream>
int s_val = 10;
int main() { std::cout << s_val << std::endl; return 0; }
|
文件结构如上,可以成功编译,main输出10
Example 2
去掉static就会报错,链接错误
一种解决方案是使用extern,告诉编译器在别的翻译单元寻找s_Val的定义
1 2 3 4 5 6 7 8 9
| #include <iostream>
extern int s_val;
int main() { std::cout << s_val << std::endl; return 0; }
|
编译运行,main的输出值是5。
Example 3
如果尝试将Static.cpp的变量修改为
1 2 3 4 5 6 7 8 9
| #include <iostream>
extern int s_val;
int main() { std::cout << s_val << std::endl; return 0; }
|
cmake编译报错undefined reference to `s_val’,因为链接器在全局作用域下找不到Static.cpp里的s_val。
类或结构体内的静态
如果类成员变量被static修饰,意味着该类的所有实例均共享同一个该静态成员变量。静态方法无法访问类的实例,因为你不知道应该访问类的哪个实例。静态类变量和静态类方法不需要通过实例进行访问。
Example 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #include <iostream>
struct Entity { static int x, y;
void Print() { std::cout << x << "," << y << std::endl; } };
int main() { Entity e; e.x = 2; e.y = 3; Entity e1; e1.x = 4; e1.y = 5; e.Print(); e1.Print(); return 0; }
|
上述代码编译失败,因为类或结构体的静态变量需要在类或结构体之外定义,类的静态成员变量需要在类外分配内存空间。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #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 = 4; e1.y = 5; e.Print(); e1.Print(); return 0; }
|
成功编译通过。
实际上修改静态成员变量可以使用如下方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| #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; Entity::x = 2; Entity::y = 3; e.Print(); return 0; }
|
静态方法同理。
Example 2
静态方法不能访问非静态成员变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| #include <iostream>
struct Entity { int x, y;
static void Print() { std::cout << x << "," << y << std::endl; } };
int main() { Entity e; e.x = 2; e.y = 3; Entity::Print(); return 0; }
|
IDE静态检查无法通过。因为每个非静态方法总是会获取当前类的一个实例作为参数。
C++中的局部静态
声明一个变量我们需要考虑两个事情,变量的生存期和变量的作用域。静态局部变量相当于在函数内部声明了一个变量,它的生命周期基本上相当于整个程序的生命周期,但是它的作用范围被限制在这个函数内部。你可以在任何作用域中声明局部静态变量,可以是函数内,也可以是if语句块内,或者其他地方。
Example 1
1 2 3 4 5 6 7 8 9 10 11 12 13
| #include <iostream>
void Func() { static int i = 0; i++; std::cout << i << std::endl; }
int main() { Func(); Func(); return 0; }
|
不多解释,输出1和2。如果去掉static,不管调用Func几次,输出都一样。