前言,这篇文章是讲解C++中static关键字的用法以及需要注意的地方。那么,static关键词的作用是什么呢?作用是控制变量的存储方式和作用范围,还会影响存储的声明周期和链接特性。
static修饰函数的局部变量,变量只在第一次调用是初始化一次,下次调用该函数不会再次初始化static修饰的变量,这个变量的声明周期是整个程序运行期间,作用域只作用于函数内
#include <iostream>
using namespace std;
#define N 99
void test(){
static int i = 0;
cout << i++ << endl;
}
int main()
{
for(int i = 0; i < N; ++i){
test();
}
return 0;
}
static修饰成员变量,需要在类外面初始化,修饰成员函数,static修饰的成员变量和成员函数在类的所有实例中是共享的,不依赖类的实例
#include <iostream>
using namespace std;
#define N 9
class MyClass{
public:
static void Test(){
cout << "调用Test()函数" << endl;
cout << MyClass::i++ << endl;
}
void PrintValue(){
cout << "调用PrintValue()函数" << endl;
cout << MyClass::i++ << endl;
}
private:
static int i;
};
int MyClass::i = 0;
int main(){
MyClass myclass_1;
MyClass myclass_2;
for(int i = 0; i < N; ++i){
if(i % 3 == 0){
myclass_1.PrintValue();
}else if(i % 3 == 1){
myclass_2.PrintValue();
}else{
MyClass::Test();
}
}
return 0;
}
需要注意静态成员函数没有this指针,不能访问任何非静态成员,因为static修饰的没有与特定的对象实例绑定
#include <iostream>
using namespace std;
class MyClass{
public:
static void Test(){
cout << "调用Test()函数" << endl;
i = 0;
}
private:
int i;
};
int main(){
MyClass::Test();
return 0;
}
上面的代码中,静态成员函数访问非静态成员变量,这是不允许的,编译会报错
所以静态成员函数时里面也不能调用非静态成员函数
#include <iostream>
using namespace std;
#define N 9
class MyClass{
public:
static void Test(){
cout << "调用Test()函数" << endl;
//cout << MyClass::i++ << endl;
PrintValue();
}
void PrintValue(){
cout << "调用PrintValue()函数" << endl;
cout << MyClass::i++ << endl;
}
private:
static int i;
};
int MyClass::i = 0;
int main()
return 0;
}
这样是不允许的,编译时就报错
static修饰成员变量,并且在多线程的情况下,需要注意变量竞态问题,比如下面的这个代码就是有问题的
#include <iostream>
#include <thread>
using namespace std;
const int N = 1000000;
class Counter {
public:
static int count;
static void Increment() {
++count;
}
static void PrintValue() {
cout << "count = " << count << endl;
}
};
int Counter::count = 0;
void threadFun() {
for (int i = 0; i < N; ++i) {
Counter::Increment();
}
}
int main() {
thread t_1(threadFun);
thread t_2(threadFun);
t_1.join();
t_2.join();
Counter::PrintValue();
return 0;
运行程序发现,结果并没有等于N的2倍,那是因为多线程竞态问题,解决方法是在每次修改静态成员变量时需要加锁,修正的代码如下
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
const int N = 1000000;
class Counter {
public:
static int count;
static mutex mtx; //声明一个静态互斥锁
static void Increment() {
lock_guard<mutex> lock(mtx);
++count;
}
static void PrintValue() {
cout << "count = " << count << endl;
}
};
int Counter::count = 0;
mutex Counter::mtx; //定义mtx
void threadFun() {
for (int i = 0; i < N; ++i) {
Counter::Increment();
}
}
int main() {
thread t_1(threadFun);
thread t_2(threadFun);
t_1.join();
t_2.join();
Counter::PrintValue();
return 0;
}
还有需要注意的是,static修饰的全局变量的作用域限制在当前文件中,其他文件是不能对其访问的,这样可以避免全局变量命名冲突的问题。 static修饰的普通函数也一样
总结
1、static修饰函数的局部变量,变量只在第一次调用是初始化一次,下次调用该函数不会再次初始化static修饰的变量,这个变量的声明周期是整个程序运行期间,作用域只作用于函数内 2、static修饰成员变量,需要在类外面初始化,多线程的场景下需要注意竞态问题,在改变变量时需要加锁,static修饰的成员变量在类的所有实例中是共享的,不依赖类的实例 3、静态成员函数没有this指针,不能访问任何非静态成员,因为static修饰的没有与特定的对象实例绑定 4、static修饰的全局变量的作用域限制在当前文件中,其他文件是不能对其访问的,这样可以避免全局变量命名冲突的问题。static修饰的普通函数也一样。 5、static修饰的变量是存储在静态存储区(数据段