清华大学C课程第5讲课件_第1页
清华大学C课程第5讲课件_第2页
清华大学C课程第5讲课件_第3页
清华大学C课程第5讲课件_第4页
清华大学C课程第5讲课件_第5页
已阅读5页,还剩58页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第五章C++程序的结构清华大学C++语言程序设计1本章主要内容作用域与可见性对象的生存期数据与函数静态成员友元共享数据的保护编译预处理命令多文件结构和工程2作用域

作用域是一个标识符在程序正文中有效的区域。作用域开始于标识符的声明处。C++中标识符的作用域有:

函数原型作用域块作用域类作用域文件作用域

作用域与可见性3块作用域在块中声明的标识符,其作用域自声明处起,限于块中,例如:voidfun(inta){intb(a);cin>>b;if(b>0){intc;......}}c的作用域b的作用域作用域与可见性5类作用域类的成员的作用域是类作用域,在类外部只有通过对象名和成员访问符“.”来访问类的公有成员。在类外不能访问类的私有成员。

类的成员函数可以直接访问类的数据成员。作用域与可见性6文件作用域不在前述各个作用域中出现的声明,具有文件作用域,这样声明的标识符的作用域开始于声明点,结束于文件尾。作用域与可见性7可见性标识符应声明在先,引用在后。如果某个标识符在外层中声明,且在内层中没有同一标识符的声明,则该标识符在内层可见。对于两个嵌套的作用域,如果在内层作用域内声明了与外层作用域中同名的标识符,则外层作用域的标识符在内层不可见。作用域与可见性9#include<iostream>usingnamespacestd;inti;//文件作用域intmain(){i=5;{inti;//块作用域

i=7;cout<<"i="<<i<<endl;//输出7}cout<<"i="<<i;//输出5return0;}作用域与可见性例5-110对象的生存期对象都有诞生和结束的时刻。对象从诞生到结束的这段时间就是它的生存期。对象的生存期与对象的存储类型相关。静态生存期:内存中固定的数据区中存储(全局数据区)。动态生存期:内存的栈区存储。内存格局:全局数据区代码区栈区堆区11#include<iostream>usingnamespacestd;inti=5;//文件作用域intmain(){cout<<"i="<<i<<endl;return0;}i具有静态生存期对象的生存期例13动态生存期块作用域中声明的,没有用static修是的对象是动态生存期的对象(习惯称局部生存期对象)。开始于程序执行到声明点时,结束于命名该标识符的作用域结束处。对象的生存期14#include<iostream>usingnamespacestd;voidfun();intmain(){fun();fun();}voidfun(){staticinta=1;inti=5;

a++;

i++;radius的作用域仅在于此,不能用于程序正文其它地方,因而可有可无cout<<"i="<<i<<",a="<<a<<endl;}对象的生存期例运行结果:i=6,a=2i=6,a=3i是动态生存期a是静态生存期15#include<iostream>usingnamespacestd;intAverage(inti){ //声明静态局部变量,具有全局寿命,局部可见staticintsum=0,count=0; sum=sum+i;count++; returnsum/count;}intmain(){intnum,avg;//局部变量,具有动态生存期cout<<"Enternumbers(-1toquit):"; do { cin>>num; if(num!=-1)avg=Average(num); }while(num>-1); cout<<"averageis:"<<avg<<endl; return0;}17例5-3具有静态、动态生存期对象的时钟程序#include<iostream>usingnamespacestd;classClock //时钟类声明{public: //外部接口 Clock(); voidSetTime(intNewH,intNewM,intNewS);//三个形参均具有函数原型作用域 voidShowTime(); ~Clock(){}private: //私有数据成员 intHour,Minute,Second;};对象的生存期18//时钟类成员函数实现Clock::Clock() //构造函数{ Hour=0; Minute=0; Second=0;}voidClock::SetTime(intNewH,intNewM,intNewS){ Hour=NewH; Minute=NewM; Second=NewS;}voidClock::ShowTime(){ cout<<Hour<<":"<<Minute<<":"<<Second<<endl;}2019数据共享机制函数间共享数据类对象之间共享数据——静态成员不同类或对象的成员函数之间、类的成员函数与一般函数之间进行数据共享

——友元21数据与函数

函数间如何进行数据共享。数据存储在局部对象中,通过参数传递实现共享——函数间的参数传递。数据存储在全局对象中。将数据和使用数据的函数封装在类中。数据与函数22使用全局对象#include<iostream>usingnamespacestd;intglobal;voidf(){global=5;}voidg(){cout<<global<<endl;}intmain(){f();g();//输出“5”return0;}数据与函数23将函数与数据封装#include<iostream>usingnamespacestd;classApplication{public:voidf();voidg();private:intglobal;};voidApplication::f(){global=5;}voidApplication::g(){cout<<global<<endl;}intmain(){ApplicationMyApp;MyApp.f();MyApp.g();return0;}数据与函数这也是类应用的另一种方式。25类对象之间共享数据类中有一些属性归所有对象共有。每个类对象中会存储该类数据成员的拷贝。静态成员用于解决同一个类的不同对象之间数据共享问题。静态成员是“类属性”的概念。如果某个属性为整个类所共有,不属于任何一个具体对象,则采用static关键字来声明为静态成员。26私有型静态数据成员

#include<iostream>usingnamespacestd;classPriClass{staticintnum; //私有型静态成员public: voidsetnum(inti){num=i;}; voidshownum(){cout<<"Thenumis:"<<num<<"\n";}};intPriClass::num; //在类外定义numintmain(){ PriClassa,b; a.shownum();b.shownum();

a.setnum(1000); //设置静态成员num为1000 a.shownum();b.shownum(); return0;}29静态函数成员#include<iostream>usingnamespacestd;classFunClass{ staticintcount;//静态数据成员声明public: FunClass(){count++;} ~FunClass(){count--;}

staticintGetCount(){returncount;}//静态函数成员};intFunClass::count; //静态数据成员定义intmain(){ FunClassa,b,c;cout<<"FromClass,countis"<<FunClass::GetCount()<<endl;cout<<"FromObject,countis"<<a.GetCount()<<endl; return0;}30静态成员函数举例classA{public:staticvoidf(Aa);private:intx;};voidA::f(Aa){cout<<x;//对x的引用是错误的cout<<a.x;//正确}静态成员31静态成员函数举例#include<iostream>usingnamespacestd;classApplication{public:staticvoidf();staticvoidg();private:staticintglobal;};intApplication::global=0;voidApplication::f(){global=5;}voidApplication::g(){cout<<global<<endl;}intmain(){Application::f();Application::g();return0;}静态成员32例5-4具有静态数据、函数成员的Point类#include<iostream>usingnamespacestd;classPoint //Point类声明{public: //外部接口 Point(intxx=0,intyy=0){X=xx;Y=yy;countP++;} Point(Point&p); //拷贝构造函数 intGetX(){returnX;} intGetY(){returnY;}

staticvoidGetC()

{cout<<"Objectid="<<countP<<endl;} private: //私有数据成员 intX,Y;

staticintcountP;}静态成员33Point::Point(Point&p){ X=p.X; Y=p.Y; countP++;}intPoint::countP=0;

voidmain() //主函数实现{ PointA(4,5); //声明对象A cout<<"PointA,"<<A.GetX()<<","<<A.GetY();

A.GetC(); //输出对象号,对象名引用 PointB(A); //声明对象B cout<<"PointB,"<<B.GetX()<<","<<B.GetY();

Point::GetC(); //输出对象号,类名引用}3234友元友元是C++提供的一种破坏数据封装和数据隐藏的机制。在一个类中,可以利用关键字friend将其它函数或类声明为友元。如果友元是一般函数或其他类的成员函数,称为友元函数;如果友元是一个类,则称为友元类,友元类的所有成员函数都自动成为友元函数。为了确保数据的完整性,及数据封装与隐藏的原则,建议尽量不使用或少使用友元。35友元函数友元函数是在类声明中由关键字friend修饰说明的非成员函数,在它的函数体中能够通过对象名访问private和protected成员,当然也能访问public成员。访问对象中的成员必须通过对象名。作用:增加灵活性,使程序员可以在封装和快速性方面做合理选择。友元36例5-6使用友元函数计算两点距离#include<iostream>#include<cmath>usingnamespacestd;classPoint //Point类声明{public: //外部接口 Point(intxx=0,intyy=0){X=xx;Y=yy;} intGetX(){returnX;} intGetY(){returnY;}

friendfloatDistance(Point&a,Point&b);

private: //私有数据成员 intX,Y;};友元37doubleDistance(Point&a,Point&b){doubledx=a.X-b.X;doubledy=a.Y-b.Y;returnsqrt(dx*dx+dy*dy);}intmain(){Pointp1(3.0,5.0),p2(4.0,6.0);doubled=Distance(p1,p2);cout<<"Thedistanceis"<<d<<endl;return0;}3638友元类若一个类为另一个类的友元,则此类的所有函数成员都能访问对方类的私有成员和保护成员。声明语法:将友元类名在另一个类中使用friend修饰说明。友元39友元类举例#include<iostream>usingnamespacestd;classBaseClass //定义BaseClass类{

friendclassFriClass;

//指定FriClass是它的友元类private:intnum;public:BaseClass(intn){num=n;}voiddisplay(){cout<<"Thenum:"<<num<<endl;}};40classFriClass//定义FriClass,它是BaseClass类的友元类{public://成员函数直接使用BaseClass类的私有成员

voiddisp1(BaseClassyc){cout<<"Thenumis:"<<yc.num<<endl;} voiddisp2(BaseClassyc){yc.display();}};intmain() {BaseClassa(10),b(100);//声明BaseClass类对象cout<<"BaseClass:"<<endl;a.display();b.display(); //显示a和b对象的值

FriClassfc; //声明FriClass类对象cout<<"FriClass:"<<endl;

fc.disp1(a);fc.disp2(b);

//通过fc显示a和b对象的值 return0;}3941友元关系是单向的友元关系是单向的,如果只声明B类是A类的友元,A类不会自动成为B类的友元。42共享数据的保护

数据共享会不同程度破坏数据的安全性。既共享,又保护的机制——常类型机制常引用、常对象、常成员函数、常成员数据43常引用在声明引用时用const修饰,被声明的就是常引用。不能通过常引用修改所引用的对象。用常引用做形参,便不会意外地发生对实参的更改。

const类型说明符&引用名共享数据的保护44常引用做形参通过引用做形参有两个理由:函数通过形参可以改变实参的值;在函数执行中形实结合时,不需要给形参分配内存。如果被传递的参数要占用大量的存储空间,则使用引用传递将更有效。在这种情况下,如果不希望函数修改实参的内容,可以将参数声明为常引用。共享数据的保护45例5-7常引用做形参#include<iostream>usingnamespacestd;voiddisplay(constdouble&r);intmain(){doubled(9.5);display(d);return0;}voiddisplay(constdouble&r)//常引用做形参,在函数中不能更新r所引用的对象。{cout<<r<<endl;}共享数据的保护46常对象常对象的数据成员值在对象的整个生存期间内不能被改变。常对象必须进行初始化,而且不能被更新。声明常对象的语法形式为:const类名对象名47常对象举例#include<iostream>usingnamespacestd;classZRF{public:ZRF(inti){num=i;cout<<"ZRFisconstructed\n";}~ZRF(){cout<<"ZRFisdestructed\n";} voiddisp(){cout<<"Thevalueofnumis:"<<num<<endl;} intnum;};intmain(){constZRFx(10);//声明常对象

x.num=20; //error1对常对象的成员赋值

x.disp(); //error2不能通过常对象调用普通的成员函数

return0;}48用const修饰的成员常成员函数使用const关键字说明的函数。常成员函数不更新对象的数据成员。常成员函数说明格式:

类型说明符函数名(参数表)const;

这里,const是函数类型的一个组成部分,因此在实现部分也要带const关键字。const关键字可以被用于参与对重载函数的区分通过常对象只能调用它的常成员函数。常数据成员使用const说明的数据成员。成员函数不可以对常数据成员赋值,初值只能通过初始化列表得到。共享数据的保护49例5-8常成员函数举例#include<iostream>usingnamespacestd;classR{public:R(intr1,intr2){R1=r1;R2=r2;}voidprint();voidprint()const;private:intR1,R2;};共享数据的保护50voidR::print(){cout<<R1<<":"<<R2<<endl;}voidR::print()const{cout<<R1<<";"<<R2<<endl;}intmain(){Ra(5,4);a.print();//调用voidprint()

constRb(20,52);

b.print();//调用voidprint()const}4651编译预处理预处理发生在程序编译之前,可以涉及如下方面:

—将其它文件包含在要编译的文件中;—定义标识符—程序代码的条件编译所有的预处理程序指令都以#开头,并且在一行预处理程序指令中,只有空白字符才能出现在前面。预处理程序指令不是C++语句,语句结尾不用加分号(;)。在开始编译前,预处理程序指令就已经完全处理好了。

52编译预处理命令#include包含指令将一个源文件嵌入到当前源文件中该点处。#include<文件名>按标准方式搜索,文件位于C++系统目录的include子目录下#include"文件名"首先在当前目录中搜索,若没有,再按标准方式搜索。#define宏定义指令定义符号常量,很多情况下已被const定义语句取代。定义带参数宏,已被内联函数取代。在C++中用来定义标识符#undef删除由#define定义的宏,使之不再起作用。53条件编译指令

#if和#endif#if常量表达式

//当“常量表达式”非零时编译程序正文#endif......编译预处理命令54条件编译指令——#else #if常量表达式

//当“常量表达式”非零时编译程序正文1#else

//当“常量表达式”为零时编译程序正文2#endif编译预处理命令55条件编译指令#elif#if常量表达式1

程序正文1

//当“常量表达式1”非零时编译#elif常量表达式2

程序正文2

//当“常量表达式2”非零时编译#else

程序正文3

//其它情况下编译#endif编译预处理命令56条件编译指令#ifdef标识符程序段1#else程序段2#endif如果“标识符”经#define定义过,且未经undef删除,则编译程序段1,否则编译程序段2。编译预处理命令57条件编译指令#ifndef标识符程序段1#else程序段2#endif如果“标识符”未被定义过,则编译程序段1,否则编译程序段2。编译预处理命令58多文件结构(例5-10)一个源程序可以划分为多个源文件:类声明文件(.h文件)

函数原型、常量定义、类声明、其他类型声明等类实现文件(.cpp文件)类的使用文件(main()所在的.cpp文件)利用工程来组合各个文件。59不使用条件编译的头文件//main.cpp#include""#include""intmain(){…}//#include"head.h"…//#include"head.h"…//head.h…classPoint{…}…多文件结构60使用条件编译的头文件//head.h#ifndefHEAD_H#defineHEAD_H…classPoint{…}…#endif多文件结构61综合案例——王婆卖瓜问题

王婆卖瓜,每卖一个瓜要记录该瓜的重量,还要记录所卖出的总重量和总个数。西瓜类设计三个数据成员:weight是一个西瓜的重量,它属于某个西瓜的total_weight和total_number是所有卖了的西瓜所共有的。把这两个数据成员声明为静态数据成员。西瓜类包含如下成员函数:卖瓜用构造函数模拟,退瓜用析构函数模拟显示瓜重用函数disp()显示总重和总数的静态成员函数total_disp()62//watermelon.h类的外部接口#ifndefWATERMELON_H#defineWATERMELON_Hclasswatermelon{ floatweight;

staticfloattotal_weight;//静态数据成员声明

staticinttotal_number;//静态数据成员声明public: watermelon(floatw);//模拟售瓜 ~watermelon(); //模

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论