《清华大学C课程课件第5讲》由会员分享,可在线阅读,更多相关《清华大学C课程课件第5讲(67页珍藏版)》请在金锄头文库上搜索。
1、1,第五章 C+程序的结构,清华大学,C+语言程序设计,2,本章主要内容,作用域与可见性 对象的生存期 数据与函数 静态成员 友元 共享数据的保护 编译预处理命令 多文件结构和工程,3,作用域,作用域是一个标识符在程序正文中有效的区域。作用域开始于标识符的声明处。C+中标识符的作用域有: 函数原型作用域 块作用域 类作用域 文件作用域,作用域与可见性,4,函数原型的作用域,函数原型中的参数,其作用域始于 “(“,结束于“)“。 例如,设有下列原型声明: double Area(double radius);,radius 的作用域仅在于此,不能用于程序正文其它地方,因而可有可无。,作用域与可见
2、性,5,块作用域,在块中声明的标识符,其作用域自声明处起,限于块中,例如: void fun(int a) int b(a); cinb; if (b0) int c; ,作用域与可见性,6,类作用域,类的成员的作用域是类作用域,在类外部只有通过对象名和成员访问符“.”来访问类的公有成员。在类外不能访问类的私有成员 。 类的成员函数可以直接访问类的数据成员。,作用域与可见性,7,文件作用域,不在前述各个作用域中出现的声明,具有文件作用域,这样声明的标识符的作用域开始于声明点,结束于文件尾。,作用域与可见性,8,可见性,可见性是从对标识符的引用的角度来谈标识符的有效性。 可见性表示从内层作用域向
3、外层作用域“看”时能看见什么。 如果标识在某处可见,则就可以在该处引用此标识符。,作用域与可见性,9,可见性,标识符应声明在先,引用在后。 如果某个标识符在外层中声明,且在内层中没有同一标识符的声明,则该标识符在内层可见。 对于两个嵌套的作用域,如果在内层作用域内声明了与外层作用域中同名的标识符,则外层作用域的标识符在内层不可见。,作用域与可见性,10,#include using namespace std; int i; /文件作用域 int main() i=5; int i; /块作用域 i=7; cout“i=“iendl; /输出7 cout“i=“i; /输出5 return 0
4、; ,作用域与可见性,例 5-1,11,对象的生存期,对象都有诞生和结束的时刻。对象从诞生到结束的这段时间就是它的生存期。对象的生存期与对象的存储类型相关。 静态生存期:内存中固定的数据区中存储(全局数据区)。 动态生存期:内存的栈区存储。,内存格局: 全局数据区 代码区 栈区 堆区,12,静态生存期,这种生存期与程序的运行期相同。 在文件作用域中声明的对象具有这种生存期。 在函数内部声明静态生存期对象,要冠以关键字static 。,对象的生存期,13,#include using namespace std; int i=5; /文件作用域 int main() cout“i=“iendl;
5、 return 0; i具有静态生存期,对象的生存期,例,14,动态生存期,块作用域中声明的,没有用static修是的对象是动态生存期的对象(习惯称局部生存期对象)。 开始于程序执行到声明点时,结束于命名该标识符的作用域结束处。,对象的生存期,15,#include using namespace std; void fun(); int main() fun(); fun(); void fun() static int a=1; int i=5; a+; i+; radius 的作用域仅在于此,不能用于程序正文其它地方,因而可有可无 cout“i=“i“,a=“aendl; ,对象的生存期
6、,例,运行结果: i=6, a=2 i=6, a=3 i是动态生存期 a是静态生存期,16,例:求数据序列的平均值static局部变量的持续效果,要求: 计算当前所有输入数据的平均值。 方法: 使用静态局部变量,使累加和持续保持。 原因: static局部变量是具有静态生存期的局部变量,具有全局的寿命和局部的可见性。,17,#include using namespace std; int Average(int i) /声明静态局部变量,具有全局寿命,局部可见 static int sum = 0, count = 0; sum = sum + i; count+; return sum /
7、 count; int main() int num,avg; /局部变量,具有动态生存期 cout num; if(num != -1) avg= Average(num); while(num -1); cout “ average is: “ avg endl; return 0; ,18,例5-3具有静态、动态生存期对象的时钟程序,#include using namespace std; class Clock /时钟类声明 public: /外部接口 Clock(); void SetTime(int NewH, int NewM, int NewS); /三个形参均具有函数原型作
8、用域 void ShowTime(); Clock() private: /私有数据成员 int Hour,Minute,Second; ;,对象的生存期,/时钟类成员函数实现 Clock:Clock() /构造函数 Hour=0; Minute=0; Second=0; void Clock:SetTime(int NewH, int NewM, int NewS) Hour=NewH; Minute=NewM; Second=NewS; void Clock:ShowTime() coutHour“:“Minute“:“Secondendl; ,20,Clock globClock; /声
9、明对象globClock, /具有静态生存期,文件作用域 int main() /主函数 cout“First time output:“endl; /引用具有文件作用域的对象: globClock.ShowTime(); /对象的成员函数具有类作用域 globClock.SetTime(8,30,30); Clock myClock(globClock); /声明具有块作用域的对象myClock cout“Second time output:“endl; myClock.ShowTime(); /引用具有块作用域的对象 ,21,21,数据共享机制,函数间共享数据 类对象之间共享数据 静态成
10、员 不同类或对象的成员函数之间、类的成员函数与一般函数之间进行数据共享 友元,22,数据与函数,函数间如何进行数据共享。 数据存储在局部对象中,通过参数传递实现共享函数间的参数传递。 数据存储在全局对象中。 将数据和使用数据的函数封装在类中。,数据与函数,23,使用全局对象,#include using namespace std; int global; void f() global=5; void g() coutglobalendl; int main() f(); g(); /输出“5” return 0; ,数据与函数,24,应避免使用不必要的全局变量,全局变量存储在全局数据区内,
11、在整个执行过程中,它们都会占用内存,而不只是在需要时才占用内存。 在可以使用局部变量的地方使用全局变量会降低函数的通用性,由于这样的函数依赖于在其外部定义的变量。 太多的全局变量会带来未知的、预料不到的副作用。,25,将函数与数据封装,#include using namespace std; class Application public: void f(); void g(); private: int global; ; void Application:f() global=5; void Application:g() coutglobalendl;,int main() Appl
12、ication MyApp; MyApp.f(); MyApp.g(); return 0; ,数据与函数,这也是类应用的另一种方式。,26,类对象之间共享数据,类中有一些属性归所有对象共有。 每个类对象中会存储该类数据成员的拷贝。 静态成员用于解决同一个类的不同对象之间数据共享问题。 静态成员是“类属性”的概念。如果某个属性为整个类所共有,不属于任何一个具体对象,则采用static关键字来声明为静态成员。,27,静态成员,静态数据成员 用关键字static声明 该类的所有对象维护该成员的同一个拷贝 在类的声明中仅仅对静态数据成员进行引用性声明,必须在类外定义和初始化,用(:)来指明所属的类。
13、 静态成员函数 类外代码可以使用类名和作用域操作符(:)来调用静态成员函数。 静态成员函数一般用来引用属于该类的静态数据成员或静态成员函数。,静态成员,28,公有静态数据成员,#include using namespace std; class PubClass public: static int num; /公有静态数据成员的声明 void shownum() cout “The num is:“num endl; ; int PubClass:num; /在类外定义num int main() PubClass a, b; PubClass:num = 1000; /通过类名访问静态成
14、员num a.shownum(); b.shownum(); a.num = 2000; /通过对象访问静态成员num a.shownum(); b.shownum(); return 0; ,29,私有型静态数据成员,#include using namespace std; class PriClass static int num; /私有型静态成员 public: void setnum(int i) num = i; ; void shownum() cout “The num is:“num “n“; ; int PriClass:num; /在类外定义 num int main(
15、) PriClass a, b; a.shownum(); b.shownum(); a.setnum(1000); /设置静态成员num为1000 a.shownum(); b.shownum(); return 0; ,30,静态函数成员,#include using namespace std; class FunClass static int count; /静态数据成员声明 public: FunClass() count+; FunClass() count-; static int GetCount() return count; /静态函数成员 ; int FunClass:count; /静态数据成员定义 int main() FunClass a, b, c; cout “From Class, count is “ FunClass:GetCount() endl; cout “From Object, count is “ a.GetCount() endl; return 0; ,31,静态成员函数举例,class A public: static void f(A a); private: int x; ; void A:f(A a) coutx; /对x的引用是错误的 couta.x; /正确 ,静态成员,32,静态成员