C++ 对象的生存期

对象(包括简单变量)都有诞生和消失的时刻。对象诞生到结束的这段时间就是它的生存期。在生存期内,对象将保持它的状态(即数据成员的值),变量也将保持它的值不变,直到它们被更新为止。对象的生存期可以分为静态生存期动态生存期

1.静态生存期

如果对象的生存期与程序的运行期相同,则称它具有静态生存期。

(1)在命名空间作用域中声明的对象都具有静态生存期。比如说,全局变量。

【例1】

#include<iostream>
using namespace std;
int i = 10;//i为全局变量,具有静态生存期
int fun1(int a=i)
{
	i = a;//给i重新赋值为传给形参a的值50
	return i;
}
int fun2(int a=i)
{
	return i;
}
int main()
{
	cout << "i=" << fun1(50) << endl;//通过调用函数fun1返回变量i的值
	cout << "i=" << fun2(20) << endl;//通过调用函数fun2返回变量i的值
	cout << "i=" << i << endl;//直接输出变量i的值
	return 0;
}

运行结果及分析:
因为在fun1函数中给全局变量i重新赋值为传给形参a的值,主函数中传给fun1函数的形参为50,所以给全局变量i重新赋值为50。因此主函数中无论是调用fun2函数,还是在主函数中直接输出i的值,结果都为50。又因为变量i是全局变量,所以它生存期与程序的运行期相同,整个程序运行结束时才消失。
在这里插入图片描述
【例2】

int i = 10;//i为全局变量,具有静态生存期
int fun1(int a=i)
{
	return i;
}
int fun2(int b=i)
{
	return i;
}

int main()
{
	cout << "i=" << fun1(50) << endl;
	cout << "i=" << fun2(20) << endl;
	cout << "i=" << i << endl;
	return 0;
}

运行结果及分析:
因为函数fun1和函数fun2只是通过传参的方式返回全局变量i的值,并没有真正改变i的值,所以在主函数中无论给函数fun1和fun2传任何整型类型的参数,输出的结果都为10。因为变量i是全局变量,所以它生存期与程序的运行期相同,整个程序运行结束时才消失。
在这里插入图片描述

(2)如果要在函数内部的局部作用域中声明具有静态生存期的对象,则要关键字 static。

例如下面语句定义的变量i便是具有静态生存期的变量,也称为静态局部变量(静态变量)

int i = 10;//i为全局变量,具有静态生存期
int fun(int a)
{
	static int i = a;//i为静态局部变量,具有静态生存期(全局寿命),局部可见
	i=i+1;
	return i;
}
int main()
{
	cout << "i=" << fun(20)<<endl;//输出的是fun函数中静态变量i的值
	cout << "i=" << fun(30)+2 << endl;//输出的是fun函数中静态变量i加2的
	cout << "i=" << i << endl;//输出的是全局变量i的值
	return 0;
}

运行结果及分析:
在fun函数中,定义变量i时加了关键字static使得变量i为静态变量,所以该变量i只在调用fun函数时起作用,在fun函数之外,仍然是全局变量i在起作用,所以第一次输出i的值为21。当fun第一次返回i的值为21之后,下一次再调用fun函数时无论传参的值时多少,fun函数中的变量i的值在一开始仍然为第一次返回的值21,然后执行语句i=i+1;,i的值变为22,第二次返回i的值为22,然后主函数中第二次输出i的值的时候又给22加2,所以第二次输出i的值为24。第三次输出的i的值是全局变量i的值,所以第三次输出i的值为10。说明在函数fun中通过static定义了变量i的值并赋值之后就不可以再通过调用fun函数进行传参来修改变量i的值,且此静态变量i的值只可以在函数fun的函数体中进行修改。
在这里插入图片描述
局部作用域中静态变量的特点是:
它并不会随着每次函数调用而产生一个副本,也不会随着函数返回而失效。也就是说,当一个函数返回后,下一次调用时,该变量还会保持上一回的值,及时发生了递归调用,也不会为该变量建立新的副本,该变量会在每次调用间共享。
在定义静态变量的同时可以给它赋初值,如:static int i = 20;,这表示i会被赋予20初始化,但是并不是每次执行函数时都将i赋值为20。
【注意】在定义时未指定初值的基本类型静态生存期变量,会被赋予0初始化,而对于动态生存期变量,不指定初值意味着初值不确定。

2.动态生存期

除了上述的两种情况,其余对象都具有动态生存期。块作用域中声明的,没有用static修饰的对象是动态生存期的对象。在局部作用域中声明的具有动态生存期的对象,习惯上也称为局部生存期对象。动态生存期对象开始于程序执行到声明点时,结束于命名该标识符的作用域结束处。局部生存期对象诞生于声明点,结束于声明所在块执行完毕时。

【例1】变量的生存期于可见性
#include<iostream>
using namespace std;

int i = 1;//i为全局变量,具有静态生存期
void other()
{
	//a、b为静态局部变量,具有全局寿命,局部可见,只第一次进入函数时被初始化
	static int a = 2;
	static int b;
	int c = 10;//c为局部变量,具有动态生存期,每次进入函数时都初始化
	a += 2;
	i += 32;
	c += 5;
	cout << "other:   " << endl;
	cout << "i: " << i << "  a: " << a << "  b: " << b << "  c: " << c << endl;
	b = a;//b=4
}
int main()
{
	static int a;//a为静态局部变量,具有全局寿命,局部可见,只第一次进入函数时被初始化
	//b,c为局部变量,具有动态生存期
	int b =-10;
	int c = 0;
	cout << "main:   " << endl;
	cout << "i: " << i << "  a: " << a << "  b: " << b << "  c: " << c << endl;
	c += 8;//c=8
	other();
	cout << "main:   " << endl;
	cout << "i: " << i << "  a : " << a << "  b : " << b << "  c : " << c << endl;
	i += 10;
	other();
	return 0;
}

运行结果及分析:
在命名空间作用域中定义全局变量i,在主函数中,定义a为静态局部变量,b,c为局部变量,在other函数中定义a、b为静态局部变量,c为局部变量。
当程序从主函数开始运行,第一次输出主函数main中的i,a,b,c的值时,由于i是全局变量,所以输出1;a是静态局部变量但没有赋初值,所以输出0;b在定义时初始化为-10,所以输出-10;c在定义时初始化为0,所以输出0。**因此第一次输出主函数中的i,a,b,c的值分别为1,0,-10,0。**在主函数中第一次输出i,a,b,c的值之后,将c的值变为8。
主函数main第一次调用other函数,在other函数输出i,a,b,c的值之前,在other函数中给局部静态变量a赋初值为2,没有给局部静态变量b赋初值,所以默认为0,定义局部变量c并初始化为10。然后给静态局部变量a+2,a的值变为4,给全局变量i+32,i的值变为33,给局部变量c+5,c的值变为15,所以第一次输出other函数中的i,a,b,c的值分别为33,4,0,15。 在other函数第一次输出i,a,b,c的值之后,将a的值赋给b,b=4。
第二次输出主函数main中的i,a,b,c的值时,由于在other函数中将全局变量i的值变为了33,所以全局变量i在之后的所有程序中应用到的值都为33,a的值仍然为一开始在主函数中定义的静态局部变量a的默认值0,局部变量b的值也没有发生改变仍然为-10,由于在主函数中第一次输出i,a,b,c的值之后,将c的值变为8,所以此时主函数中c的值应为8。**因此第二次输出主函数中的i,a,b,c的值分别为33,0,-10,8。**在主函数中第二次输出i,a,b,c的值之后,给全局变量i的值加10,即33+10,此时全局变量i的值为43,且全局变量i在之后的所有程序中应用到的值都为43。
主函数第二次调用other函数,在other函数输出i,a,b,c的值之前,给静态局部变量a+2,由于第一次在other函数结束时,a的值为4,现在再给a+2,所以a的值就变为6;给全局变量i+32,由于在主函数中将全局变量i的值变为了43,所以i的值为75;局部变量c则没有改变仍然为15;由于在other函数第一次输出i,a,b,c的值之后,将a的值4赋给静态局部变量b,b=4,所以,在第二次调用other函数时,静态局部变量b的值仍然为上一次other函数结束时b的值4。因此第二次输出other函数中的i,a,b,c的值分别为75,6,4,15。
在这里插入图片描述

【例2】具有静态和动态生存期对象的时钟程序。
#include<iostream>
using namespace std;

class Clock//定义时钟类
{
public://外部接口
	Clock();
	void setTime(int newH, int newM, int newS);//3个形参均具有函数原型作用域
	void showTime();
private:
	int hour, minute, second;//私有数据成员
};

//时钟类成员函数的实现
Clock::Clock():hour(0),minute(0),second(0){}//构造函数
void Clock::setTime(int newH, int newM, int newS)//3个形参都具有局部作用域
{
	hour = newH;
	minute = newM;
	second = newS;
}

void Clock::showTime()
{
	cout << hour << ":" << minute << ":" << second << endl;
}

Clock globClock;// 声明对象globClock,具有静态生存期,命名空间作用域
//由默认构造函数初始化为0:0:0

int main()
{
	cout << "第一次输出时间为:" << endl;

	//引用具有命名空间作用域的对象globClock
	globClock.showTime();	//显示0:0:0

	globClock.setTime(8, 30, 30);//将时间设置为8:30:30

	Clock myClock(globClock);//声明具有块作用域的对象myClock
	//调用默认的拷贝构造函数,以globClock的值为初值

	cout << "第二次输出时间为:" << endl;
	myClock.showTime();//引用具有块作用域的对象myClock
	return 0;
}

运行结果及分析:
对象globClock为全局变量,具有静态生存期,命名空间作用域。在主函数中,引用对象globClock访问showTime函数时,因为globClock没有初始化,所以它由默认构造函数初始化为0:0:0,所以第一次输出的时间为0:0:0,然后全局对象globClock调用setTime函数,将时间设置为为了8:30:30,由于globClock是全局对象,所以在之后的程序中应用对象globClock的值都为8:30:30。然后定义了Clock类的局部对象myClock,并调用默认的拷贝构造函数,以对象globClock的值8:30:30初始化对象myClock,接下来引用局部对象myClock访问showTime函数时,由于局部对象myClock的值被初始化为globClock的值8:30:30,所以第二次输出的时间为8:30:30。
在这里插入图片描述
在这个程序中,包含了具有各种作用域类型的变量和对象。其中时钟类定义中函数成员setTime的三个形参具有函数原型作用域;setTime函数定义中的3个参数以及主函数中的对象myClock都具有局部作用域;时钟类的数据、函数成员具有类作用域;对象globClock具有命名空间作用域。在主函数中,这些变量、对象以及对象的公有成员都是可见的。就生存期而言,除了命名空间作用域的对象globClock具有静态生存期,与程序运行期相同之外,其他变量及对象都具有动态生存期。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值