static关键字有什么作用?
这也算是面经中老生常谈的问题了,看来不懂的同学没有好好的刷面经啊。
那么本文就来好好解释一下这个问题。
C++的static关键字主要的功能有:改变作用域 、改变变量在内存模型中的存储位置。修饰不同的变量会有不同的效果,现在我们来一一说明。
先放总结:
(1)static修饰全局变量,该变量作用域由global变成当前文件
(2)static修饰全局函数,该函数作用域由global变成当前文件
(3)static修饰函数局部变量,该变量生命周期从原本贯穿函数调用期间,变成贯穿整个程序,但其作用域依然局限在所在函数作用域。
(4)static修饰类的成员变量或成员函数,称为静态成员,静态成员被类的所有对象共有。静态成员具有以下特性:
- 静态成员被类的所有对象所共有
- this指针无法指向静态成员
- 静态函数无法更改或调用非静态成员
- 静态成员可以直接用类调用,如:Family::static_var,Family::static_func()
为了方便,代码验证使用Visual Studio 2019,建议读者也把下面代码手敲运行一遍。
修饰全局变量
当一个变量被定义成全局变量时,该变量的作用域为global,全局变量可以跨文件使用。当用static修饰成员变量时,该变量的作用域仅在当前文件。
未用static进行修饰
测试代码如下:
c++
// file.cpp
int cs = 1;
// another_file.cpp
#include <iostream>
extern int cs;
int main() {
std::cout << "全局变量cs=" << cs << std::endl;
return 0;
}
测试实况:
输出结果:
使用static修饰全局变量
测试代码如下:
c++
// file.cpp
static int cs = 1;
// another_file.cpp
extern int cs;
int main() {
std::cout << "全局变量cs=" << cs << std::endl;
return 0;
}
测试实况:
输出结果:
IDE提示链接错误,这就是因为变量cs的作用域仅限file.cpp,在another_file.cpp无法访问到cs
结论
static关键字修饰全局变量时会使其作用域从全局变成当前文件范围。
修饰全局函数
static修饰全局函数时,效果和全局变量一样,也是将其作用域从全局变成了当前文件范围。
未使用static修饰
测试代码:
c++
// file.cpp
int add(int a, int b) {
return a + b;
}
// another_file.cpp
#include <iostream>
extern int add(int a, int b);
int main() {
std::cout << add(2, 3) << std::endl;
return 0;
}
测试实况:
测试结果:
在another_file.cpp可以正常调用file.cpp中的全局函数。
使用static修饰全局函数
测试代码:
c++
// file.cpp
static int add(int a, int b) {
return a + b;
}
// another_file.cpp
#include <iostream>
extern int add(int a, int b);
int main() {
std::cout << add(2, 3) << std::endl;
return 0;
}
测试实况:
测试结果:
链接失败。
结论
同全局变量一样,用static修饰全局函数后,该函数的作用域从全局变成当前文件。
修饰函数中的局部变量
用static修饰函数的局部变量时,延长局部变量的生命周期,使其贯穿整个程序。
c++
// test_func.cpp
#include <iostream>
void func() {
int a = 1;
static int b = 1;
std::cout << "a=" << a++ << ", b=" << b++ << std::endl;
}
int main() {
for (int i = 0;i < 5; i++) {
func();
}
return 0;
}
测试结果:
局部变量a,在每次函数调用都会被重新赋值,生命周期仅限于函数调用期间。
而被static修饰的局部变量b在每次函数调用后都会持续增加,函数调用结束后也不会被销毁,生命周期持续到程序结束。
结论
static修饰函数局部变量时,会延长该局部变量的生命周期,直到程序结束。
这是因为未被修饰的局部存在栈中,函数调用结束后,该栈空间会被回收,连带成员变量一起回收。
而被static的函数成员变量存在内存模型中的"常量区",该区域的变量会直到程序结束才会被销毁。
修饰类成员
被static类的成员变量或成员函数称为静态成员,该静态成员会归属于类,被所有该类实例化的对象共享。举个例子,静态成员就像家里的空调,是所有家庭成员共享的,所有家庭成员都能使用,且不独属于某个家庭成员。
但是静态成员有几个特点
(1)不能在静态成员函数修改非静态成员变量或者调用非静态成员函数
(2)静态成员可以直接用类访问:Family::air
(3)this指针无法指向静态成员:this->air 会报错
测试代码:
c++
#include <iostream>
#include <string>
class Family {
public:
static int air; // 静态成员变量声明
std::string role;
Family(std::string role) : role(role) {}
static void static_printAir() {
std::cout << "全家一起用空调,当前 air=" << air << std::endl;
}
void printAir() {
std::cout << this->role <<"使用空调," << "当前 air=" << air << std::endl;
}
};
// 静态成员变量定义(必须在类外)
int Family::air = 20;
int main() {
Family husband("丈夫");
Family wife("妻子");
Family::air++;
Family::static_printAir(); // 输出: 当前 air=21
husband.air++; // 修改静态成员变量
husband.printAir(); // 输出: 当前 air=22
wife.air++; // 再次修改静态成员变量
wife.printAir(); // 输出: 当前 air=23
husband.static_printAir(); // 类实例对象也可以调用静态成员函数
return 0;
}
测试结果:
结论
静态成员被类的所有成员共同拥有
this指针无法指向静态成员