static那些事

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)静态成员:

  1. 用static修饰成员变量,即为静态成员变量;用static修饰成员方法,即为静态成员方法
  2. 静态成员属于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、非静态成员函数可以调用类的静态成员函数吗?
答案:可以,因为静态成员为所有类对象所共享,不受访问限制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值