static用法小结

static用法小结:


static意为静态的
C++中的static有两种用法:

1.面向过程设计中的static//应用于普通变量和函数,不涉及类
2.面对对象程序设计中的static//主要说明static在类中的作用

一:面向过程设计中的static

1.静态全局变量

在全局变量前,加上关键字static,该变量就被定义成为一个静态全局变量。
例:

#include<iostream>

using namespace std;

static int a;//定义静态全局变量

int main()
{
    cout << "a = "<<a;
    cin.get();
    return 0;
}

输出结果为:

a = 0

静态全局变量有以下特点:

①该变量在全局数据区分配内存;
②未经初始化的静态全局变量会自动初始化为0(非静态变量的值是随机的)
③静态全局变量在本文件内可见,而在文件之外是不可见的

对于一个程序,在内存中的发布情况为:
代码区
全局变量区
堆区
栈区
一般由new产生的动态数据存放在堆区,函数内部的自动变量存放在栈区。自动变量一般会随着函数的退出而释放空间。而静态数据(即使在函数内部的静态局部变量)存放在全局数据区。全局数据区的数据不会因为函数的退出而释放空间。
此外:
定义静态全局变量有以下好处:

①静态全局变量不能被其他文件使用。(这意味着static可屏蔽extern关键字)
②在其他文件中可以声明具有相同名字的变量,不会发生冲突。

2.静态局部变量

在局部变量前加上关键字static,该变量就被定义成为一个静态局部变量。
例:

#include<iostream>

using namespace std;

void fn();

int main()
{
    fn();
    fn();
    fn();
    cin.get();
    return 0;
}

void fn()
{
    static int n = 10;
    cout << "n = "<<n<<endl;
    n++;
}

输出结果为:

n = 10
n = 11
n = 12

当去掉关键字static后,输出结果为:

n = 10
n = 10
n = 10

可见:在函数内部定义的变量,会随着函数的退出而消亡,因此三次输出结果均为

n = 10

而当加入static关键字后,局部变量并不会随着函数的退出而消亡,因此会出现三次不同的输出结果。
静态局部变量有以下特点:

• 该变量在全局数据区分配内存;
• 静态局部变量在程序执行到该对象的声明处时被首次初始化,即以后的函数调用不再进行初始化;
• 静态局部变量一般在声明处初始化,如果没有显式初始化,会被程序自动初始化为0;
• 它始终驻留在全局数据区,直到程序运行结束。但其作用域为局部作用域,当定义它的函数或语句块结束时,其作用域随之结束;

通常,在函数体内定义了一个变量,每当程序运行到该语句时都会给该局部变量分配栈内存。但随着程序退出函数体,系统就会收回栈内存,局部变量也相应失效。但有时候我们需要在两次调用之间对变量的值进行保存。通常的想法是定义一个全局变量来实现。但这样一来,变量已经不再属于函数本身了,不再仅受函数的控制,给程序的维护带来不便。
静态局部变量正好可以解决这个问题。静态局部变量保存在全局数据区,而不是保存在栈中,每次的值保持到下一次调用,直到下次赋新值

3.静态函数

在函数的返回类型前加上关键字static,函数就被定义为静态函数。静态函数与不同函数不同,它只能在声明它的文件中使用,不能被其他文件使用。
例:

#include<iostream>

using namespace std;

static void fn();//声明静态函数

int main()
{
    fn();
    cin.get();
    return 0;
}

void fn()
{
    int n = 10;
    cout << "n = "<<n<<endl;
}

输出结果为:

n = 10

静态函数的好处:

• 静态函数不能被其它文件所用;
• 其它文件中可以定义相同名字的函数,不会发生冲突;

二:面向对象中的static(类中的static关键字)

1.静态数据成员
在类中数据成员的声明前加上static关键字,该数据成员就是类中的静态数据成员。
例:

//CForQt.cpp
#include<iostream>

using namespace std;

class MyClass
{
public:
	void GetMyclass();//获取班级名
	void Show();//显示班级名
private:
	static int myclass;//声明静态数据成员:myclass
};

int MyClass::myclass = 0;//初始化静态数据成员

int main()
{
	MyClass a;
	a.GetMyclass();
	cout << "a";
	a.Show();//获取班级a的名称并显示
	MyClass b;
	b.GetMyclass();
	cout << "b";
	b.Show();//获取班级b的名称并显示
	cout << "a";
	a.Show();//显示班级a的名称
	cin.get();
	cin.get();
	return 0;

}

void MyClass::GetMyclass()
{
	cin >> myclass;
}
void MyClass::Show()
{
	cout << "的班级为:" << myclass<<endl;
}

输出结果为:

11
a的班级为:11
12
b的班级为:12
a的班级为:12

当我们删除***int MyClass::myclass = 0;//初始化静态数据成员***时,编译器(msvc)报错:

1>------ 已启动生成: 项目: CForQt, 配置: Debug Win32 ------
1>CForQt.cpp
1>CForQt.obj : error LNK2001: 无法解析的外部符号 “private: static int MyClass::myclass” (?myclass@MyClass@@0HA)
1>C:\Users\31951\source\repos\CForQt\Debug\CForQt.exe : fatal error LNK1120: 1 个无法解析的外部命令
1>已完成生成项目“CForQt.vcxproj”的操作 - 失败。
========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0 个 ==========

可以看出,静态数据成员有以下特点:
①静态数据成员为所有类对象所共享。对类的多个对象来说,静态数据成员只分配一次内存,供所有对象共用。对于任何一个类对象来说,静态数据成员的值都是一样的
②静态数据成员存储在全局数据区。静态数据成员定义时要分配空间,所以不能在类声明中定义。
③静态数据成员必须初始化,并且唯一初始化方式为:<数据类型> <类名>::<静态数据成员名>=<值>
例:

int MyClass::myclass=0;

④静态数据成员和普通数据成员一样遵从public,protected,private访问规则;
⑤因为静态数据成员在全局数据区分配内存,供本类的所有对象使用。所以,它不属于特定的类对象,在没有产生类对象时其作用域就可见,即在没有产生类的实例时,我们就可以操作它;
⑥ 类的静态数据成员有两种访问形式:
<类对象名>.<静态数据成员名> 或 <类类型名>::<静态数据成员名>

如果静态数据成员的访问权限允许的话(即public的成员),可在程序中,按上述格式来引用静态数据成员;

同全局变量相比,使用静态数据成员有两个优势:

  1. 静态数据成员没有进入程序的全局名字空间,因此不存在与程序中其它全局名字冲突的可能性;
  2. 可以实现信息隐藏。静态数据成员可以是private成员,而全局变量不能;

二:静态成员函数

与静态数据成员一样,我们也可以创建一个静态成员函数,它为类的全部服务而不是为某一个类的具体对象服务。静态成员函数与静态数据成员一样,都是类的内部实现,属于类定义的一部分。

静态成员函数与静态数据成员类似,有以下特点:

①静态成员函数属于整个类而非类的对象,因此它没有this指针
②静态成员函数可以访问静态成员函数和静态数据成员。但是不能访问非静态成员函数和非静态数据成员
③非静态成员函数可以访问静态成员函数和静态数据成员
④不能将静态成员函数定义为虚函数
⑤调用静态成员函数,可以用成员访问操作符(.)和(->)为一个类的对象或指向类对象的指针调用静态成员函数,也可以直接使用如下格式:
<类名>::<静态成员函数名>(<参数表>)
调用类的静态成员函数。
⑥为了防止父类的影响,可以在子类定义一个与父类相同的静态变量,以屏蔽父类的影响。这里有一点需要注意:我们说静态成员为父类和子类共享,但我们有重复定义了静态成员,这会不会引起错误呢?不会,我们的编译器采用了一种绝妙的手法:name-mangling 用以生成唯一的标志。
⑦static并没有增加程序的时空开销,相反她还缩短了子类对父类静态成员的访问时间,节省了子类的内存空间。

static 变量可能会导致线程安全的问题

参考:
C++中的static关键字的总结
C++中static关键字作用总结

本人能力有限,若有错误,敬请斧正。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值