资源描述
,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,单击此处编辑母版标题样式,前一页,休息,第五章,C+,程序的结构,黑龙江大学计算机学院,软件学院,阚忠良,C+,语言程序设计,1,本章主要内容,作用域与可见性,对象的生存期,数据与函数,静态成员,共享数据的保护,友元,编译预处理命令,多文件结构和工程,2,函数原形的作用域,函数原型中的参数,其作用域始于,(,,结束于,),。,例如,设有下列原型声明:,double Area(double radius);,radius,的作用域仅在于此,不能用于程序正文其它地方,因而可有可无。,作用域与可见性,3,块作用域,在块中声明的标识符,其作用域自声明处起,限于块中,例如:,void,fun(int,a),int,b(a);,cin,b;,if(b0),int,c;,.,c,的作用域,b,的作用域,作用域与可见性,4,类和文件作用域,类作用域作用于特定的成员名,类及其对象有特殊的访问和作用域规则。,不在前述各个作用域中出现的声明,具有文件作用域,这样声明的标识符的作用域开始于声明点,结束于文件尾。,作用域与可见性,5,类,X,的成员,M,在下列情况下具有类作用域,:,在,X,的成员函数内出现的标识符,M,同时没有声明同名的局部变量,M.,ss.M,X:M,ptr,-M,6,可见性,可见性是从对标识符的引用的角度来谈的概念,可见性表示从内层作用域向外层作用域,“,看,”,时能看见什么。,如果标识在某处可见,则就可以在该处引用此标识符。,块作用域,类作用域,文件作用域,作用域与可见性,7,可见性,标识符应声明在先,引用在后。,在同一作用域中,不能声明同名的标识符。,如果某个标识符在外层中声明,且在内层中没有同一标识符的声明,则该标识符在内层可见。,对于两个嵌套的作用域,如果在内层作用域内声明了与外层作用域中同名的标识符,则外层作用域的标识符在内层不可见。,作用域与可见性,8,#include,int,i,;/,文件作用域,int,main(),i,=5;,int,i,;/,块,作用域,i,=7;,cout,i=,i,endl,;/,输出,7,cout,i=,i,;/,输出,5,return 0;,作用域与可见性,例,5.1,9,对象的生存期,对象从产生到结束的这段时间就是它的生存期。,在对象生存期内,对象将保持它的值,直到被更新为止。,10,静态生存期,这种生存期与程序的运行期相同。,在文件作用域中声明的对象具有这种生存期。,在函数内部声明静态生存期对象,要冠以关键字,static,。,对象的生存期,11,#include,int,i,=5;/,文件作用域,int,main(),cout,i=,i,endl,;,return 0;,i,具有静态生存期,对象的生存期,例,12,动态生存期,块作用域中声明的对象是动态生存期的对象(习惯称局部生存期对象)。,开始于程序执行到声明点时,结束于命名该标识符的作用域结束处。,对象的生存期,13,#include,void fun();,void main(),fun();,fun();,void fun(),static,int,a,=1;,int,i,=5;,a,+;,i,+;,cout,i=,i,a=,a,endl,;,运行结果:,i=6,a=2,i=6,a=3,i,是动态生存期,a,是静态生存期,对象的生存期,例,14,例,5-2,变量的生存期与可见性,#include,int,i,=1;,void main(void),static,int,a,;,int,b,=-10;,int,c,=0;,void other(void);,cout,-MAIN-n;,cout,i:,i,a:,a,b:,b,c:,c,endl,;,c=c+8;other();,cout,-MAIN-n;,cout,i:,i,a:,a,b:,b,c:,c,endl,;,i,=,i,+10;other();,对象的生存期,15,void other(void),static,int,a,=2;,static,int,b,;,int,c,=10;,a,=,a,+2;,i,=,i,+32;,c,=,c,+5;,cout,-OTHER-n;,cout,i:,i,a:,a,b:,b,c:,c,endl,;,b,=,a,;,16,运行结果:,-MAIN-,i:1,a:0 b:-10 c:0,-OTHER-,i:33,a:4 b:0 c:15,-MAIN-,i:33,a:0 b:-10 c:8,-OTHER-,i:75,a:6 b:4 c:15,17,例,5-3,具有静态、动态生存期对象的时钟程序,#include,class Clock,public:,Clock();,void,SetTime(int,NewH,int,NewM,int,NewS,);/,三个形参均具有函数原型作用域,void ShowTime();,Clock(),private:,int,Hour,Minute,Second;,;,对象的生存期,18,/,时钟类成员函数实现,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(),cout,Hour:Minute:Second,endl,;,19,Clock,globClock,;,void main(),cout,First time output:,endl,;,globClock.ShowTime,();,/,对象的成员函数具有类作用域,globClock.SetTime(8,30,30);,Clock,myClock(globClock,);,/,声明具有块作用域的对象,myClock,cout,Second time output:,endl,;,myClock.ShowTime,();,/,引用具有块作用域的对象,myClock,20,程序的运行结果为:,First time output:,0:0:0,Second time output:,8:30:30,21,数据与函数,数据存储在局部对象中,通过参数传递实现共享,函数间的参数传递。,数据存储在全局对象中。,将数据和使用数据的函数封装在类中。,例,例,22,#include,int,global,;,void f(),global,=5;,void g(),cout,global,endl,;,int,main(),f();,g();/,输出,“,5,”,return 0;,23,#include,class Application,public:,void,f,();void,g,();,private:,int,global,;,;,void Application:,f,(),global,=5;,void Application:,g,(),cout,global,endl,;,int,main(),Application,MyApp,;,MyApp.f,();,MyApp.g,();,return 0;,24,静态成员,静态数据成员,用关键字,static,声明,该类的所有对象维护该成员的同一个拷贝,必须在类外定义和初始化,用,(:),来指明所属的类。,静态成员函数,类外代码可以使用类名和作用域操作符来调用静态成员函数。,静态成员函数只能引用属于该类的静态数据成员或静态成员函数。,静态成员,25,例,5-4,具有静态数据成员的,Point,类,#include,class Point,public:,Point(int,xx=0,int,yy,=0)X=xx;Y=,yy,;,countP,+;,Point(Point,int,GetX,()return X;,int,GetY,()return Y;,void,GetC,(),cout,Object id=,countP,endl,;,private:,int,X,Y;,static,int,countP,;,;,静态成员,26,Point:Point(Point&p),X=p.X;,Y=p.Y;,countP,+;,int,Point:countP,=0;,void main(),Point A(4,5);,cout,Point A,A.GetX,(),A.GetY,();,A.GetC,();,Point B(A);,cout,Point B,B.GetX,(),B.GetY,();,B.GetC,();,27,#include,class Application,public:,static,void f();,static,void g();,private:,static,int,global;,;,int,Application:global=0;,void Application:f(),global=5;,void Application:g(),cout,global,endl,;,静态成员函数举例,int,main(),Application,:f();,Application,:g();,return 0;,28,静态成员函数举例,class A,public:,static void f(A a);,private:,int,x;,;,void A:f(A a),cout,x,;/,对,x,的引用是,错误,的,cout,a.x;/,正确,29,例,5-5,具有静态数据、函数成员的,Point,类,#include,class Point/Point,类声明,public:/,外部接口,Point(int,xx=0,int,yy,=0)X=xx;Y=,yy;countP,+;,Point(Point/,拷贝构造函数,int,GetX,()return X;,int,GetY,()return Y;,static void,GetC,(),cout,Object id=,countP,endl,;,private:/,私有数据成员,int,X,Y;,static,int,countP,;,静态成员,30,Point:Point(Point&p),X=p.X;,Y=p.Y;,countP,+;,int,Point:countP,=0;,void main()/,主函数实现,Point A(4,5);/,声明对象,A,cout,Point A,A.GetX,(),A.GetY,();,A.GetC,();/,输出对象号,对象名引用,Point B(A);/,声明对象,B,cout,Point B,B.GetX,(),B.GetY,();,Point:GetC,();/,输出对象号,类名引用,31,友元,友元是,C+,提供的一种破坏数据封装和数据隐藏的机制。,通过将一个模块声明为另一个模块的友元,一个模块能够引用到另一个模块中本是被隐藏的信息。,可以使用友元函数和友元类。,为了确保数据的完整性,及数据封装与隐藏的原则,建议尽量不使用或少使用友元。,32,友元函数,友元函数是在类声明中由关键字,friend,修饰说明的非成员函数,在它的函数体中能够通过对象名访问,private,和,protected,成员,作用:增加灵活性,使程序员可以在封装和快速性方面做合理选择。,访问对象中的成员必须通过对象名。,友 元,33,例,5-6,使用友元函数计算两点距离,#include,#include,class Point/Point,类声明,public:/,外部接口,Point(int,xx=0,int,yy,=0)X=xx;Y=,yy,;,int,GetX,()return X;,int,GetY,()return Y;,friend float,Distance,(Point,private:/,私有数据成员,int,X,Y;,;,友 元,34,double Distance(Point&a,Point&b),double,dx,=,a,.X,-b,.X;,double,dy,=,a,.Y-,b,.Y;,return,sqrt(dx,*,dx+dy,*,dy,);,int,main(),Point p1(3.0,5.0),p2(4.0,6.0);,double d=Distance(p1,p2);,cout,The distance is d,endl,;,return 0;,35,友元类,若一个类为另一个类的友元,则此类的所有成员都能访问对方类的私有成员。,声明语法:将友元类名在另一个类中使用,friend,修饰说明。,友 元,36,友元类举例,class A,friend class B,;,public:,void Display(),cout,x,endl,;,private:,int,x;,class B,public:,void,Set(int,i);,void Display();,private:,A,a;,;,友 元,37,void,B:Set(int,i),a.x,=i;,void B:Display(),a.Display();,38,常类型,常类型的对象必须进行初始化,而且不能被更新。,常引用:被引用的对象不能被更新。,const,类型说明符,&,引用名,常对象:,必须进行初始化,不能被更新。,类名,const,对象名,常数组:数组元素不能被更新,(,下一章介绍,),。,类型说明符,const,数组名,大小,.,常指针:指向常量的指针,(,下一章介绍,),。,共享数据的保护,39,例,5-7,常引用做形参,#include,void display(,const,double,int,main(),double d(9.5);,display(d);,return 0;,void display(,const,double&r),/,常引用做形参,在函数中不能更新,r,所引用的对象。,cout,r,endl,;,共享数据的保护,40,常对象举例,class A,public:,A(int,i,int,j)x=i;y=j;,.,private:,int,x,y;,;,A,const,a(3,4);/a,是常对象,不能被更新,共享数据的保护,41,用,const,修饰的对象成员,常成员函数,使用,const,关键字说明的函数。,常成员函数不更新对象的数据成员。,常成员函数说明格式:,类型说明符 函数名(参数表),const;,这里,,const,是函数类型的一个组成部分,因此在实现部分也要带,const,关键字。,const,关键字可以被用于参与对重载函数的区分,通过常对象只能调用它的常成员函数。,常数据成员,使用,const,说明的数据成员。,共享数据的保护,42,例,5-8,常成员函数举例,#,include,class R,public:,R(int,r1,int,r2)R1=r1;R2=r2;,void print();,void print(),const,;,private:,int,R1,R2;,;,共享数据的保护,43,void R:print(),cout,R1:R2,endl,;,void R:print()const,cout,R1;R2,endl,;,void main(),R a(5,4);,a.print();/,调用,void print(),const R b(20,52);,b.print();,/,调用,void print()const,44,例,5-9,常数据成员举例,#include,class A,public:,A(int,i);,void print();,const,int,private:,const,int,a;,static const,int,b;/,静态常数据成员,;,共享数据的保护,45,const,int,A:b=10;,A:A(int,i):a(i),r(a),void A:print(),cout,a:b:r,endl,;,void main(),/*,建立对象,a,和,b,,,并以,100,和,0,作为初值,分别调用构造函数,通过构造函数的初始化列表给对象的常数据成员赋初值*,/,A a1(100),a2(0);,a1.print();,a2.print();,46,编译预处理命令,#include,包含指令,将一个源文件嵌入到当前源文件中该点处。,#include,按标准方式搜索,文件位于,C+,系统目录的,include,子目录下,#include,文件名,首先在当前目录中搜索,若没有,再按标准方式搜索。,#define,宏定义指令,定义符号常量,已被,const,定义语句取代。,定义带参数宏,已被内联函数取代。,#,undef,删除由,#define,定义的宏,使之不再起作用。,47,条件编译指令,#if,和,#,endif,#if,常量表达式,/,当,“,常量表达式,”,非零时编译,程序正文,#,endif,.,编译预处理命令,48,条件编译指令,#else,#if,常量表达式,/,当“常量表达式”非零时编译,程序正文,1,#else,/,当,“,常量表达式,”,为零时编译,程序正文,2,#,endif,编译预处理命令,49,条件编译指令,#,elif,#if,常量表达式,1,程序正文,1,/,当,“,常量表达式,1,”,非零时编译,#,elif,常量表达式,2,程序正文,2,/,当,“,常量表达式,2,”,非零时编译,#else,程序正文,3,/,其它情况下编译,#,endif,编译预处理命令,50,多文件结构(例,5-10,),一个源程序一般至少分为三个源文件:,类声明文件(,.h,文件),类实现文件(,.,cpp,文件),类的使用文件(,main(),所在的,.,cpp,文件,),利用工程来组合各个文件。,51,不使用条件编译的头文件,/,main.cpp,#include,file1.h,#include,file2.h,void main(),/file1.h,#include,head.h,/,file2.h,#include,head.h,/head.h,class Point,多文件结构,52,使用条件编译的头文件,/,/,head.h,#,ifndef,HEAD_H,#define HEAD_H,class Point,#,endif,多文件结构,53,例,5-7,程序实例,-,人员信息管理程序,使用静态成员,文件结构,54,实验,4,实现客户机(,Client),类。定义字符型静态数据成员,ServerName,,,保存其服务器名称;整型静态数据成员,ClientNum,,,记录客户机数量;静态函数,ChangeServerName,(),改变服务器名称。在头文件,client.h,中定义类,在文件,client.cpp,中实现,在文件,test.cpp,中测试这个类,观察相应的成员变量的取值的变化情况。,55,56,作业:,复习第五章,预习第六章,5-13,、,5-14 5-11,实验四,57,
展开阅读全文