您好,欢迎访问三七文档
第六章程序结构16.1对象的作用域与可见性作用域是指标识符的作用范围或有效范围,可见性是从对标识符引用的角度来谈的概念,若标识符在某处可见,则就可以在该处引用该标识符。这里所说的标识符主要是指变量名或者对象名。16.1.1对象的作用域例子#includeiostream.hintid01=3;voidmain(){intid=5;{intid;id=7;coutid=idendl;//输出7}coutid=idendl;//输出5coutid01endl;//输出3}1.函数原形的作用域函数原形的作用域是指函数原型中标识符形参的作用范围,其作用域始于函数原形的左括号“(”,结束于函数原形声明的右括号“)”。例如,设有下列原型声明:doubleArea(doubleradius);等价形式:doubleArea(double);radius的作用域仅在函数的左右括号之间,不能用于程序正文其它地方,因而radius参数可有可无,省略它,也不会影响程序的编译效果,但是,考虑到可读性,还是在函数原形中给出形参说明比较好。需要说明的是,这里函数原形的作用域是针对函数声明中的对象形参而言的,而不是指函数实现中的对象形参。2.块作用域块作用域是指在块中声明的标识符,其作用域自声明处起,一直到块结束为止。由于该作用域的范围具有局部性,所以有些文献也把它叫作局部作用域。例如:#includeiostream.hvoidfun(intx)//x的作用域从此处开始{inty=x;//y的作用域从此处开始ciny;if(y0){intz;//z的作用域从此处开始z=x+y;}//z的作用域到此处结束}//x和y的作用域到此处结束这里,y和z都具有块作用域,并且是不同的块作用域。所谓块是指用一对花括号“{”和“}”括起来的一段程序。在本例中,函数体是一个块,if语句后的分支部分又是一个较小的块,二者是包含的关系。3.类作用域类的作用域是指类的声明中一对花括号所形成的作用范围,简称类域。每一个类都具有该类的类域,该类的成员局部于该类所属的类域中,一个类的某个成员可以引用该类的其他成员,或者说类的某个成员对同一类的其他成员具有无限制的访问权。在类作用域之外,对类成员的访问一般是不允许的,或者要受特殊的规则的限制(如使用友元函数)。在C++中,由于类中成员的特殊访问规则,使得类中成员的作用域变得比较复杂。具体地讲,某个类A的某个成员M在下情况下具有类A的作用域:1)该成员M出现在该类的某个成员函数中,并且该成员函数没有定义同名标识符。2)该类A的某个对象的该成员M的表达式中。例如,设x是A的对象,则在表达式x.M中。3)在该类A的某个指向对象指针的该成员M的表达式中。例如,设pt一个指向A类对象的指针,则在表达式pt-M中。4)在使用作用域操作符所限定的该成员中。例如,在表达式A::M中。需要强调说明的是,类作用域不同于文件域,在类作用域中定义的变量不能使用auto、register和extern等修饰符,只能用static修饰符,而定义的函数也不能用extern修饰符。另外,在类作用域中的静态成员和成员函数还具有外部的连接属性。一般说来,类作用域介于文件作用域和块作用域之间,由于类作用域问题比较复杂,只能根据实际情况,具体问题具体分析。4.文件作用域不在前述各个作用域中出现的声明,具有文件作用域,这样声明的标识符的作用域开始于声明点,结束于文件尾。由此可以看出,文件作用域是在所有函数之外说明的。一般来说,在文件开始所定义的全局标识符就具有全局作用域,从这个意义上说文件作用域也叫全局作用域。不同位置定义的同名标识符有不同的作用域,要注意区别。16.1.2对象的可见性可见性是从对标识符的引用的角度来谈的概念,如果标识符在某处可见,则表示在该处可以引用该标识符。作用域指的是标识符的有效范围,而可见性是分析在某个位置标识符的有效性。在作用域中,文件作用域最大,接着依次是类作用域和块作用域,作用域的一般关系见图6.1所示。可见性表示从内层作用域向外层作用域“看”时能看见什么,可见性和作用域之间有着紧密的联系。图6.1作用域关系图作用域可见性的一般如下:·标识符应声明在先,引用在后。·在同一作用域中,不能声明同名的标识符。·如果某个标识符在外层中声明,且在内层中没有同一标识符的声明,则该标识符在内层可见。·对于两个嵌套的作用域,如果在内层作用域内声明了与外层作用域中同名的标识符,则外层作用域的标识符在内层不可见。例6.1作用域与可见性示例。#includeiostreamusingnamespacestd;intx;//定义全局变量,具有文件作用域voidmain(){x=3;//给文件作用域的变量赋初值3块作用域类作用域文件作用域{intx;//子块中定义局部变量,具有块作用域x=5;coutx=xendl;//输出5}coutx=x;//输出3}在本例中,主函数外声明的变量x具有文件作用域,其有效作用范围是整个源程序文件。在主函数开始处给文件作用域的变量赋初值3接着在子块中声明同名变量并赋初值5,第一次输出结果为5,这是因为具有块作用域的变量把具有文件作用域的同名变量给屏蔽掉了,即具有文件作用域的变量在块中变得不见。当程序运行到子块结束后,第二次输出的结果才是具有文件作用域的变量值3。需要说明的是,在局部变量的作用域内,可用使用作用域操作符“::”对隐藏的同名全局变量进行访问。例6.2作用域操作符使用示例。#includeiostream.hdoublea;//全局变量intb;//全局变量enum{Red,White,Blue};//全局枚举voidmain(){inta;//局部变量doubleb;//局部变量enum{Blue,White,Red};//局部枚举a=5;//给局部变量赋值::a=2.5;//给全局变量赋值b=4.5;::b=4;coutaendl;cout::aendl;coutsizeof(b)endl;//显示双精度浮点数占用的内存数coutsizeof(::b)endl;//显示整型数占用的内存数cout(int)Blueendl;//显示enum型局部值cout(int)::Blueendl;//显示enum型全局值}程序运行结果:52.5840216.2对象的生存期无论是简单变量还是类的对象都有产生和结束的时刻。变量或对象从产生到结束的这段时间就是它的生存期。在对象生存期内,对象将保持它的值,直到其被更新为止。1.静态生存期若对象的生存期与程序的运行期相同,则称该对象具有静态生存期。下面两种情况的对象具有静态生存期:1)在文件作用域中声明的对象具有这种生存期。2)在函数内部声明静态生存期对象,要冠以关键字static。由此可见,只有文件作用域中声明的对象或块作用域中用关键字static声明的对象才具有静态生存期。例6.3静态生存期示例。#includeiostream.hintx=5;//文件作用域voidmain(){coutx=xendl;}在本例中,变量x具有静态生存期。2.动态生存期上述两种情况除外的对象都具有动态生存期。块作用域中直接声明的对象是动态生存期的对象,习惯也称作局部生存期对象。动态生存期对象开始于程序声明点,结束于命名该标识符的作用域结束处。例6.4动态生存期示例。#includeiostream.hvoidfun();voidmain(){fun();fun();}voidfun(){staticinta=1;inti=5;a++;i++;couti=i,a=aendl;}在本例中,变量a具有静态生存期,变量x具有动态生存期。根据生存期的不同,可以把对象划分成如下三种:1)局部对象:当对象被声明时调用构造函数,该对象被创建,当程序退出定义该对象所在的函数体或程序块时,调用析构函数,释放该对象。2)静态对象:当程序第一次执行所声明的静态对象时,该对象被创建,当程序结束时,该对象被释放。3)全局对象:当程序开始时,调用构造函数创建该对象,当程序结束时调用析构函数释放该对象。局部对象是被定义在一个函数体或程序块内的,它的作用域小,生存期也短,这种对象具有块作用域和动态生存期。静态对象是被定义在一个文件中,它的作用域从定义时起到文件结束时止。它的作用域比较大,它的生存期也比较大,这种对象具有静态生存期。全局对象是被定义在某个文件中,而它的作用域却在包含该文件的整个程序中,它的作用域是最大的,它的生存期也是长的,该对象具有静态生存期。例6.5对象的静态、动态生存期示例。#includeiostreamusingnamespacestd;classTime//声明时间类{private:inthour,minute,second;//私有数据成员public://外部接口Time();voidSetTime(inth,intm,ints);//三个形参具有函数原形作用域voidShowTime();~Time(){};};//时钟类成员函数定义Time::Time()//构造函数{hour=0;minute=0;second=0;}voidTime::SetTime(inth,intm,ints)//设置时间成员函数{hour=h;minute=m;second=s;}voidTime::ShowTime()//显示时间成员函数{couthour':'minute':'secondendl;}Timeg_time;//声明全局对象g_time,具有静态生存期voidmain(){coutOutputtime1=;//引用具有文件作用域的对象g_timeg_time.ShowTime();//对象的成员函数具有类作用域coutendl;g_time.SetTime(10,29,29);Timel_time(g_time);//声明局部对象l_time,具有动态生存期coutOutputtime2=;//引用具有块作用域的对象l_timel_time.ShowTime();coutendl;}程序运行结果:Outputtime1=0:0:0Outputtime2=10:29:29在本例程序中,包含了各种作用域类型的变量或对象,其中时间类声明中的成员函数SetTime的三个形参具有函数原形作用域,对象l_time等具有块作用域,时间类的数据成员和成员函数具有类作用域,对象g_time具有文件作用域。在主函数中,对象及其公有成员都是可见的。在主函数之外声明的对象g_time具有静态生存期、文件作用域,该对象是通过构造函数对其作初始化。在主程序中,首先输出时间0:0:0;接着将对象g_time的时间设置为10:29:29;然后声明具有块作用域的对象l_time,它具有动成生存期,并用g_time对其作初始化,此时调用默认的拷贝函数将g_time对象的数据成员值赋给l_time,因此对象l_time和g_time具有完全相同的数据,输出对象l_time的时间为10:29:29。6.3对象的存储类型简单变量具有以下4种存储类型:·auto:采用堆栈方式分配内存空间,属于暂时性存储,其存储空间可以被若干变量多次覆盖使用。·register:存储在通用寄存器中。·extern:在所有函数和程序段中都可引用。·static:在内存中以固定地址存放,在整个程序运行期间都有效。其中,static关键字除用于简单变量外,还可用于将类的成员声明为静态成员,以解决同一个类的不同对象之间的数据和函数的共享问题。但各种形式的数据共享又会不同程度地破坏数据安全。因此,对于既需要共享、又需要防止改变的数据应该声明为常量进行保护,因为常量在程序运行期间是不可改变的。声明对象时,可以使用const进行修饰,称之为常量对象。本节首先讲解con
本文标题:第6章程序结构
链接地址:https://www.777doc.com/doc-2197577 .html