1.static定义
static是C/C++中常用的修饰符,它被用来控制变量的存储方式和可见性,提高内存利用率和安全性,但也有一些限制和注意事项。
2.static修饰局部变量
(1) static修饰的局部变量,叫静态局部变量,静态局部变量只初始化一次,而且延长了局部变量的生命周期,直到程序运行结束后才释放。
下面的代码中,func函数中定义了一个静态局部变量a,因为是静态,所以每次调用函数,a的值不再重新赋值而是只保留上次函数调用结束时的值,可以继续a++进行计数;
而func2中的b是非静态,所以函数结束后,它也会销毁,函数开始时,它又被重新初始化,所以每次执行函数输出b,都是1;
void func()
{
static int a = 0;//静态局部变量,只初始化一次,程序运行结束后释放,生命周期长
a++;
cout << a;
}
void func2()
{
int b = 0;//普通局部变量,生命周期短
b++;
cout << b;
}
int main()
{
for (int i = 0; i < 5; i++)
{
func();
}
cout << endl;
for (int i = 0; i < 5; i++)
{
func2();
}
return 0;
}
从输出结果可以看出静态局部变量的作用
12345
11111
注意:
① 如果定义局部变量时不给他赋初值,那么对于静态变量来说,编译时自动赋初值0,或空字符 ‘\0’ ,对于自动变量来说,它的值是不确定的。
② 虽然静态局部变量在函数调用结束后仍然存在,但是其他函数不能引用它,因为是局部变量,只能被本函数引用,而不能被其他函数引用。
3.static修饰全局变量
static修饰全局变量的时候,这个全局变量只能在本文件中访问,不能再其他文件中访问,即便是extern外部声明也不可以。所以如果我们希望全局变量仅限于在本源文件中使用,在其他源文件中不能引用,就可以通过在全局变量之前加上关键字 static 来实现,使全局变量被定义成为一个静态全局变量。
因为全局变量本身是具有外部链接属性的,即全局变量的作用域是整个工程,但如果用static修饰全局变量,就会使全局变量失去外部链接属性,变成内部链接属性,即只能在自己的文件中使用,所以static修饰全局变量时,只能在自己当前文件中使用。
//test1.cpp
int g_num = 100;
//test2.cpp
extern int g_num; //先用extern声明外部变量
int main()
{
cout << g_num; //可以正常输出,不会报错
}
但如果使用static修饰全局变量,就会报错
//test1.cpp
static int g_num = 100;
//test2.cpp
extern int g_num; //先用extern声明外部变量
int main()
{
cout << g_num; //错误 LNK2001 无法解析的外部符号 "int g_num" (?g_num@@3HA)
}
总结:如果我们希望全局变量仅限于在本源文件中使用,在其他源文件中不能引用,也就是说限制其作用域只在定义该变量的源文件内有效,而在同一源程序的其他源文件中不能使用。 这时,就可以通过在全局变量之前加上关键字 static 来实现,使全局变量被定义成为一个静态全局变量。
4.static修饰函数
函数默认是有外部链接属性的,但是被static修饰后,会使得函数失去外部链接属性,变成内部链接属性。所以static修饰的函数只能在自己所在的文件内部使用,不能再其他文件中使用。和static修饰的全局变量很像。
//test1.cpp
int add(int a, int b)//定义一个函数
{
return a + b;
}
//test2.cpp
extern int add(int a, int b);//声明外部符号
int main()
{
cout << add(1, 2) << endl;//可以正常调用,不会报错
}
而在函数前加一个static修饰,就会报错
//test1.cpp
static int add(int a, int b)//定义一个函数
{
return a + b;
}
//test2.cpp
extern int add(int a, int b);//声明外部符号
int main()
{
cout << add(1, 2) << endl;//错误 LNK2019 无法解析的外部符号 "int __cdecl add(int,int)" (?add@@YAHHH@Z),函数 main 中引用了该符号
}
5.类和静态
(1)静态成员:
- 用static修饰成员变量,即为静态成员变量;用static修饰成员方法,即为静态成员方法
- 静态成员属于class本身。
(2)静态成员的特征和实践验证:
1️⃣:静态成员为所有类对象所共享,不属于某个具体的实例
2️⃣:静态成员变量必须在类外定义,定义时不添加static关键字
3️⃣:静态成员函数没有隐藏的this指针,不能访问任何非静态成员
4️⃣:访问静态成员变量的特殊方式
5️⃣:静态成员和类的普通成员一样,也有public、protected、private3种访问级别,也可以具有返回值
1️⃣静态成员为所有类对象所共享,不属于某个具体的实例
class A
{
private:
static int _n;
int _k;
char _a;
};
int main()
{
cout << sizeof(A) << endl; //8
return 0;
}
这里的运行结果为8,这里的计算规则是按照C语言那套计算结构体大小的规则。并没有把我静态成员变量_n考虑进去,因为静态成员变量属于整个类,是类的所以对象,所以静态变量成员不计入总大小。
2️⃣ 静态成员变量必须在类外定义,定义时不添加static关键字
class A
{
private:
//声明
static int _n;
static int _k;
};
//定义
int A::_n = 0;
int A::_k = 0;
可以看到类中声明的静态成员,必须要在类外定义。
3️⃣ 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
class A
{
public:
static void Func()
{
cout << ret << endl; // err错误,访问了非静态成员,因为无this指针
cout << _k << endl; //正确
}
private:
//声明
int ret = 0;
static int _k;
};
//定义
int A::_k = 0;
4️⃣访问静态成员变量的特殊方式
当静态成员变量是public时,可用如此三种方式进行访问:
1、通过对象.静态成员访问
2、通过类名::静态成员访问
3、通过匿名对象突破类域进行访问
class A
{
public:
// 声明
static int _k;
};
// 定义
int A::_k = 0;
int main()
{
A a;
cout << a._k << endl; //通过对象.静态成员来访问
cout << A::_k << endl; //通过类名::静态成员来行访问
cout << A()._k << endl;//通过匿名对象突破类域进行访问
return 0;
}
当静态成员变量是pivate时,可用如此三种方式进行访问:
1、通过对象.静态成员访问。
2、通过类名::静态成员访问。
3、通过匿名对象调用成员函数进行访问。
class A
{
public:
static int GetK()
{
return _k;
}
private:
static int _k;
};
int A::_k = 0;
int main()
{
A a;
cout << a.GetK() << endl; //通过对象.静态成员函数来访问
cout << A::GetK() << endl;//通过类名::静态成员函数来行访问
cout << A().GetK << endl; //通过匿名对象调用成员函数进行访问
return 0;
}
5️⃣静态成员和类的普通成员一样,也有public、private、protected三种访问级别,也可以具有返回值。
1、静态成员函数可以调用非静态成员函数吗?
答案:不可以,因为静态成员函数没有this指针,无法调用非静态成员函数。
2、非静态成员函数可以调用类的静态成员函数吗?
答案:可以,因为静态成员为所有类对象所共享,不受访问限制。