1、第五章 C+程序的结构,C+语言程序设计,本章主要内容,作用域与可见性 对象的生存期 数据与函数 静态成员 共享数据的保护 友元 编译预处理命令 多文件结构和工程,5.1 作用域与生命期,5.1 作 用 域,5.2 对象的生命期,5.1 作用域,1 块作用域,4 文件作用域,2 函数原型作用域,作用域指标识符能够被使用的范围。只有在作用域内标识符才可以被访问(称为可见)。,任何标识符作用域的起始点均为标识符说明处。,下面分别介绍:,3 类的作用域,参和函数体中定义的局部变量,作用域都在该函数内,也称作函数域。,块域,块指一对大括号括起来的程序段。块中定义的标识符,作用域在块内。,复合语句是一个
2、块。,函数也是一个块。,复合语句中定义的标识符,,作用域仅在该复合语句中。,函数中定义的标识符,包括形,在块中声明的标识符,其作用域自声明处起,限于块中,例如: void fun(int a) int b(a);cinb;if (b0)int c; ,同名局部变量,服从局部优先原则在块内可以通过域运算符“:”访问同名的全局变量。, int i=0 , j=0 , k=0; int i=1 , j=1;k=i+j; / i=? j=?k=?k=i+j; / i=? j=? k=? ,函数原型作用域,函数原型不是定义函数,在作函数原型声明时,其中的形参作用域只在原型声明中,即作用域结束于右括号。正
3、是由于形参不能被程序的其他地方引用,所以通常只要声明形参个数和类型,形参名可省略。,#include void swap(int,int); void main() ,3类作用域,类作用域作用于特定的成员名。 类X的成员M具有类作用域,对M的访问方式如下: 如果在X的成员函数中没有声明同名的局部作用域标识符,那么在该函数内可以访问成员M。 通过表达式x.M或者X:M访问。 通过表达式prt-M,4 文件作用域,文件作用域也称全局作用域。定义在所有函数之外的标识符,具有文件作用域,作用域为从定义处到整个源文件结束。,如果某个文件中说明了具有文件作用域的标识符,该文件又被另一个文件包含,则该标识符
4、的作用域延伸到新的文件中。,文件中定义的全局变量和函数都具有文件作用域。,5.1.2可见性,可见性是从对标识符的引用的角度来谈的概念 可见性表示从内层作用域向外层作用域“看”时能看见什么。 如果标识在某处可见,则就可以在该处引用此标识符。,可见性,标识符应声明在先,引用在后。 如果某个标识符在外层中声明,且在内层中没有同一标识符的声明,则该标识符在内层可见。 对于两个嵌套的作用域,如果在内层作用域内声明了与外层作用域中同名的标识符,则外层作用域的标识符在内层不可见。,在同一作用域内的对象名、函数名、枚举常量名会隐藏同名的类名或枚举类型名。 重载的函数可以有相同的函数名。,例5.2,#inclu
5、de int i; /文件作用域 int main() i=5; int i; /块作用域i=7;cout“i=“iendl; /输出7cout“i=“i; /输出5return 0; ,存储类型决定了变量的生命期,变量生命期指从获得空间到空间释放之间的时期。,5.2 变量的存储类型与生命期,存储类型的说明符有四个:auto, register, static和extern。前两者称为自动类型,后两者分别为静态和外部类型。,本章重点掌握static和extern这两种类型的使用和区别。具体说,区分局部变量和静态局部变量,全局变量和静态全局变量。,auto:局部变量是自动类型。其空间分配于块始,
6、空间释放于块终,且由系统自动进行。自动变量保存在栈中,且是在程序运行过程中获得和释放空间,未初始化时值为随机数。,1 变量的存储类型,register:为提高程序运行效率,可以将某些变量保存在寄存器中,即说明为寄存器变量,不提倡使用。,static:静态变量。根据被修饰变量的位置不同,分为局部(内部)静态变量和全局(外部)静态变量。所有静态变量均存放在全局数据区,编译时获得存储空间,未初始化时自动全0,且只初始化一次。,2 静态存储类型,静态存储类型的作用域限制该变量或函数只能在定义它的文件中使用。静态全局变量在编译时分配存储空间,如果定义时不指定初值,则编译系统将其初始化为全0。,一个全局变
7、量和一个静态全局变量在使用上是不同的,其他文件通过外部变量声明可以使用一个全局变量,但却无法使用静态全局变量,静态全局变量只能被定义它的文件所独享。函数与静态函数之间的区别是相同的。,局部静态变量的作用域为块域,但生命期为整个文件。即当块结束时,局部静态变量空间仍然保持,直到整个程序文件结束时该局部静态变量空间才释放,生命期结束。,局部静态变量,【例53】 自动变量与局部静态变量的区别。(演示),#include st()static int t=100; /局部静态变量t+; return t; at()int t=100; /自动变量t+;return t; void main()int
8、i;for(i=0;i5;i+) coutat()t;coutendl;for(i=0;i5;i+) coutst()t;coutendl; ,5.2 变量的存储类型,1,2,3,4,5,101,101,101,101,101,#include st()static int t=100; /局部静态变量t+; return t; at()int t=100; /自动变量t+;return t; void main()int i;for(i=0;i5;i+) coutat()t;coutendl;for(i=0;i5;i+) coutst()t;coutendl; ,5.2 变量的存储类型,1,
9、2,101,3,4,5,102,103,104,105,3 生命期,(1)静态生命期,(2)局部生命期,(3)动态生命期,生命期(Life time)也叫生存期。生命期与存储区域相关,存储区域分为代码区、静态数据区、栈区和堆区,相应地,生命期分为静态生命期、局部生命期和动态生命期。,(1)静态生命期,静态生命期指的是标识符从程序开始运行时存在,即具有存储空间,到程序运行结束时消亡,即释放存储空间。,具有静态生命期的标识符存放在静态数据区,属于静态存储类型,如全局变量、静态全局变量、静态局部变量。具有静态生命期的标识符在未被用户初始化的情况下,系统会自动将其初始化为全0。,函数驻留在代码区,也具
10、有静态生命期。 所有具有文件作用域的标识符都具有静态生命期。,(2)局部生命期,在函数内部或块中定义的标识符具有局部生命期,其生命期开始于执行到该函数或块的标识符声明处,结束于该函数或块的结束处。具有局部生命期的标识符存放在栈区。具有局部生命期的标识符如果未被初始化,其内容是随机的,不可用。,具有局部生命期的标识符必定具有局部作用域;但反之不然,静态局部变量具有局部作用域,但却具有静态生命期。,(3)动态生命期,具有动态生命期的标识符由特定的函数调用或运算来创建和释放,如调用malloc()或用new运算符为变量分配存储空间时,变量的生命期开始,而调用free()或用delete运算符释放空间
11、或程序结束时,变量生命期结束。具有动态生命期的变量存放在堆区。关于new运算和delete运算将在指针一章中介绍。,生命期与存储区域对照,5.3 类的静态成员,静态数据成员 用关键字static声明 该类的所有对象维护该成员的同一个拷贝 必须在类外定义和初始化,用(:)来指明所属的类。 静态成员函数 类外代码可以使用类名和作用域操作符来调用静态成员函数。 静态成员函数只能引用属于该类的静态数据成员或静态成员函数。,例5-4 具有静态数据成员的 Point类,#include using namespace std; class Point public: Point(int xx=0, int
12、 yy=0) X=xx; Y=yy; countP+; Point(Point ,静态成员,Point:Point(Point ,28,Point:GetC();,静态成员函数举例,class A public:static void f(A a);private:int x; ; void A:f(A a) coutx; /对x的引用是错误的couta.x; /正确 ,静态成员,具有静态数据、函数成员的 Point类,#include using namespace std; class Point public: Point(int xx=0, int yy=0) X=xx;Y=yy;countP+; Point(Point ,静态成员,Point:Point(Point ,32,总结,存储类型决定了变量的生命期 生命期分为:静态局部,动态生命期 类的静态数据成员被所有对象所共享,必须由 类名:标示符来访问 类的静态函数可以访问类的静态数据和函数成员,但访问非静态必须通过参数对象的方式。,