版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
练习#include"stdafx.h“usingnamespacestd;boolExchange(inta,int&b,constintc,constint&d,int*e,int*f){ intsuma=a; a=b; b=suma;//c=a;//d=b; suma=c+d; cout<<"suma="<<suma<<endl; suma=*e; *e=*f; *f=suma; return1;}intmain(){ inta=3,b=6,c=9,d=12,e=15,f=18; cout<<"a="<<a<<"b="<<b<<"c="<<c<<"d="<<d<<"e="<<e<<"f="<<f<<endl; Exchange(a,b,c,d,&e,&f); cout<<"a="<<a<<"b="<<b<<"c="<<c<<"d="<<d<<"e="<<e<<"f="<<f;}第七章程序结构Chapter7
ProgramStructure
程序结构:使程序得以运行的框架组织便是程序结构,对程序结构的研究,是为了更好地表达算法思想,使其符合编译逻辑,又具有更好的可读性和可维护性学习目标:
1.从简单的函数层层调用,初步理解C++程序结构
2.学习合理组织程序的规则与经验,掌握扩展程序规模的基本方法第七章内容
函数组织(FunctionOrganization)
头文件(HeaderFiles)
全局数据(GlobalData)
静态数据(StaticData)
作用域与生命期(Scopes&Lifetime)
名空间(namespace)
预编译(Pre-Compilation)
7.1.1程序构成函数:对输入参数负责,埋头做自己的事,最终返回结果函数组织:通过在函数中进行函数调用来扩展运行的规模,层层叠叠的函数构成树结构做法:将若干个函数组织成文件,又将若干个文件构成程序的办法来进行编程分工对如下的函数调用关系,进行文件划分mainf2f1f3g1g2hp文件1文件2文件3图7-2程序结构的描述7.1.2程序文件拆分在把握总体模块结构的基础上,一般是一个函数一个函数地编写,如果有很多函数,就要分好类,分成几个程序文件来由几个程序员负责。如图7-2的程序结构,八个函数可以从一个文件拆分成三个程序文件实现,如图7-3:函数总是声明在前,调用在后。为了实现多文件结构的编程,必须在程序工程中将这些编辑好的文件加入。//函数声明
voidf1();voidf2();voidf3();…//函数定义
intmain(){f1();f2();f3();}voidf1(){…}…voidp();…voidf1(){…}voidf1();…intmain(){…}voidf1(){…}voidg1();…voidg1(){…}图7-3一个文件拆分成三个程序文件7.2头文件原始头文件:作为共同开发的项目,为了共享彼此的过程资源(函数),将全体函数声明放在一个共用的头文件中界面头文件:界定模块可用资源(函数,数据,类型等)(可由一个或几个头文件组合,其实现由他人提供),或提供他人使用的模块资源.它是由软件工程师分发的、以规范项目开发为目的的资源文件做法:练习划分函数组,模仿学习构造头文件,并注意头文件的应含内容7.2.1原始头文件函数声明只能有惟一的一次,为了方便,可以将一个程序中所有要用到的函数专门做成一个程序文件,加在每个程序文件的开始处,也就是将那些函数声明做成一个文件后缀为.h的文件(称之为头文件),用指令#include的方式加在程序文件的开始处。如在前面的多文件结构中可以先做一个abc.h的头文件,其内容为://abc.hvoidf1();voidf2();voidf3();voidg1();voidg2();voidp();voidh();原始头文件
(包含图中的一切函数声明)头文件的使用:使函数调用免于声明//a1.cpp#include”abc.h”voidf1(){
if(…){p();g1();else{g2();h();}}头文件的使用:使函数调用免于声明//a2.cpp#include”abc.h”intmain(){f1();f2();f3();}//-------voidf3(){f1();}//-------voidp(){f3();}//-------头文件的使用:使函数调用免于声明//a3.cpp#include”abc.h”voidh(){…}voidf2(){g1();g2();}//-------voidg1(){…}voidg2(){…}7.2.2界面头文件上述的规定和使用头文件的方法是很原始的,头文件更重要的作用是在设计阶段规定界面,也就是通过头文件可以明白地看出,某个程序文件提供了什么服务,这种头文件称为用户界面。界面头文件//a1.ha1.cpp提供的资源voidf1();//a2.h
a2.cpp提供的资源voidp();//a3.h
a3.cpp提供的资源voidg1();voidg2();voidf2();voidh();//a1.cpp#include”a2.h”#include”a3.h”voidf1(){
if(…){p();g1();
}else{g2();h();}}使用界面头文件//a2.cpp#include”a1.h”#include”a3.h”staticvoidf3();intmain(){f1();f2();f3();}voidf3(){f1();}voidp(){f3();}使用界面头文件//a3.cpp#include”a3.h”voidh(){…}voidf2(){g1();g2();}voidg1(){…}voidg2(){…}使用界面头文件7.2.3头文件的内容头文件的语句也要符合C++语法头文件的作用是给源程序提供可以使用的外部资源一览表,它不仅仅包括函数声明,它基本上还包括:全局数据声明,如externintn;externinta[];函数声明,如voidfn();类型声明,如classA;全局常量定义,如constfloatpi=3.14;内联函数定义,如inlinevoidfn(){…};模板声明和定义,如template<classT>classA{…};名空间定义,如namespaceN{…}类型定义,如enumCOLOR{…};classA{…};预编译指令,如#include<iostream>注释,如//2003年5月7日创建由于头文件可能出现在一个程序的若干个源程序文件中,所以将一些实体定义放在头文件中是不明智的,因为一种定义体在一个程序中只能出现一次,如:#include<iostream>intmain(){std::cout<<“helloworld!\n”;}然后,在源文件a.cpp中,写上#include”abc.h”编译运行,虽然能得到结果,但是这从根本上背离了头文件在C++程序结构体系中的作用!头文件一定不能包括:全局数据定义,如inta;函数定义,如voidfn(){…};7.3全局数据全局数据:使若干个模块在程序范围内共享(读与写)数据,是若干程序文件沟通数据的一种形式意义:模块的独立性由数据的封闭性来支持.全局数据破坏了数据的封闭性,因而对小程序简单而对规范化程序则不登大雅之堂做法:练习函数之间用参数传递数据的常规形式,尽量避免使用全局数据7.3.1全局数据访问全局数据就是在任何函数的外部声明或定义的,在程序范围内可以访问的数据。对于大多数函数都要访问某个数据的情形时,可以将它设置为全局的,就可以免于参数传递。例如:对于矩阵的输入、处理和输出vector<vector<int>>a;//globalDatavoidinput();voidtranspose();voidprint();intmain(){input();//usingatranspose();//usingaprint();//usinga}7.3.2消除全局数据全局数据破坏了模块结构的独立性,也破坏了抽象数据结构的封闭性。程序是各个独立模块的聚集,全局数据牵扯了各个模块,使其无法独立。可以通过参数传递的方法消去全局数据。如:消去全局数据:前一个过程的输出作为后一个过程的输入typedefvector<vector<int>>Mat;Matinput();Mattranspose(constMat&a);voidprint(constMat&a);intmain(){print(transpose(input()));}7.3.3一次定义原则全局数据有全局变量、全局常量、全局对象等,它们都有指针、引用、数组和其他形式。全局数据在程序存储结构中置身于全局数据区的位置。全局数据区的整个区域在程序启动时,初始化为0.在多文件结构的程序中,像单文件那样的全局数据定义形式存在着问题,因为在不同源程序文件中定义同名全局数据,就是多次构建全局数据实体,它意味着各个程序文件实际上使用的是各不相同的实体,如:80程序中的两个函数显示一个全局整型变量,却出现了不一致,原因是全局数据也应像函数那样,多次声明,而只能有一次定义。全局数据的声明形式是在全局数据定义形式前加关键字extern,如:在多个程序文件组成的程序中共享数据,要遵守一次定义规则//item1.cpp#include<iostream>usingnamespacestd;intn=8;//definevoidf();intmain(){cout<<n<<”\n”;f();}//item2.cpp#include<iostream>usingnamespacestd;externintn;//declarevoidf(){cout<<n<<”\n”;}7.3.4全局常量全局常量也是放在全局数据区,只供读取,不许修改,不会扰乱模块关系。不允许在同一个程序中反复定义全局常量,但可以在不同的程序文件中重复定义。全局常量可能被滥用,如求矩阵的和,其数据放在ab.txt中,每组数据前两个整数表示行和列,后面则是矩阵的元素,计算和然后输出。在程序中,为了求若干个矩阵的和,先定义两个最大行列数的二维数组,然后反复重用,由于数组的下标只允许为常量,因此,设置全局变量,带来的后果是,占用了不必要的空间。若行列放宽后,则必须要改程序,带来了函数划分时所引入的参数传递困难,程序如下://=====================================#include<iostream>#include<iomanip>#include<fstream>usingnamespacestd;//-------------------------------------constintrow=100;constintcol=100;intmain(){ifstreamin("ab.txt");intma[row][col];intmb[row][col];intmc[row][col];
for(intr,c;in>>r>>c;){for(inti=0;i<r;++i)for(intj=0;j<c;++j)in>>ma[i][j];for(inti=0;i<r;++i)for(intj=0;j<c;++j)in>>mb[i][j];for(inti=0;i<r;++i)for(intj=0;j<c;++j)mc[i][j]=ma[i][j]+mb[i][j];for(inti=0;i<r;++i){for(intj=0;j<c;++j)cout<<setw(4)<<mc[i][j];cout<<endl;}}该程序可以完全不用全局常量,如下列程序可以表示了一种便于函数划分、增加函数独立性的常规方法,结构更加合理,不滥用空间,不滥用全局数据,运行结果与前面程序一致.#include<iostream>#include<iomanip>#include<fstream>#include<vector>usingnamespacestd;//-------------------------------------typedefvector<vector<int>>Mat;voidinput(istream&in,Mat&a);MatmatAdd(constMat&a,constMat&b);voidprint(constMat&a);//-------------------------------------intmain(){ifstreamin("ab.txt");for(introw,col;in>>row>>col;){Mata(row,vector<int>(col));Matb=a;input(in,a);input(in,b);print(matAdd(a,b));}}//------------------------------------voidinput(istream&in,Mat&a){for(inti=0;i<a.size();++i)for(intj=0;j<a[0].size();++j)in>>a[i][j];}//------------------------------------MatmatAdd(constMat&a,constMat&b){Matc=a;for(inti=0;i<a.size();++i)for(intj=0;j<a[0].size();++j)c[i][j]+=b[i][j];returnc;}//------------------------------------voidprint(constMat&a){for(inti=0;i<a.size();++i){for(intj=0;j<a[0].size();++j)cout<<setw(4)<<a[i][j];cout<<endl;}}7.4静态数据静态全局数据:在一个程序文件中共享的数据.注意:全局数据则在多个程序文件中共享数据静态局部数据:在屡次调用的同一个函数中共享的数据7.4.1静态全局数据在过程化程序设计中,为了使程序文件发挥模块的作用,有必要定义一种模块的局部量,它区别于其他程序文件,称之为静态全局数据(也称全局静态数据)。函数的模块性在于只与其输入/输出联系,定义的变量在程序来说是局部变量,但在该函数内部来说,却是全局的。程序文件的模块性在于只与其定义的全局函数联系,只与包含文件联系,其定义的静态全局数据对于该程序文件内部来说是全局的,但对于整个程序来说却是局部的。在程序工程中添加一个程序文件,等于添加了一个程序文件模块,意味着其他地方要使用该程序文件所定义的某些函数,在该程序文件中包含了某些头文件,意味着该程序文件要使用其他地方的函数。如根据图7-3的程序文件划分,其中a2.cpp可以得到图7-4:
a1.ha3.h程序文件模块
a2.cpp
a2.h图7-4程序文件模块f1f2p程序中,有的函数是为文件中的其他函数服务的,并不对外提供服务,这些函数应声明为静态,表示局部于程序文件。同样有的变量只是为本文件服务,也不是全局数据,应标以static,这些函数和变量称为静态全局数据和静态全局变量,它只在本文件范围内可见,在其他程序文件中不可见。没有静态全局常量,前述的全局常量可以看做是文件变量,每个程序文件都可以通过”constinta=3;”的形式来定义惟一的文件域全局常量,即静态全局常量,这就是为什么可以将全局常量写入头文件的原因。全局常量有内部链接性(文件范围内有效)7.4.2静态局部数据函数中的变量为局部变量,在定义局部变量前面加上static,就成了静态局部变量,静态局部变量驻留在全局数据区,默认初始化值为0,而且不会受函数的调用和返回的影响,函数第一次被调用时,静态局部变量被建立,此后该变量一直存在,直到程序运行结束。静态局部变量在函数内部定义,但却驻留在全局数据区,所以,从可见性来说,它与局部变量一致,从生命期来说,它与全局变量一致。下面的程序演示了全局变量、静态局部变量和局部变量的区别:#include<iostream>usingnamespacestd;//-------------------------------------voidfunc();intn=1;//-------------------------------------intmain(){inta=0,b=-10;cout<<"a="<<a<<",b="<<b<<",n="<<n<<endl;func();cout<<"a="<<a<<",b="<<b<<",n="<<n<<endl;func();}//------------------------------------voidfunc(){staticinta=2;intb=5;a+=2,b+=5;n+=12;cout<<"a="<<a<<",b="<<b<<",n="<<n<<endl;}//====================================a=0,b=-10,n=1a=4,b=10,n=13a=0,b=-10,n=13a=6,b=10,n=25
由于静态局部变量是局部的,所以若把该变量的指针作为函数返回值到处传播是不妥的,而且也丧失了模块的独立性,因为任何依附于某个块的操作都必须依赖于某个块而不能独立。7.5作用域与生命期作用域:有很多种,变化最多的是局部作用域.作用域遵守就近原则,它总是取用最贴近的名字,除非名字加前缀,则指特定区域的名字生命期:实体一旦产生(定义)后,存活时间的度量作用域与生命期:作用域是编程规范,用于编译时的语法检查,生命期是程序运行中的实体存活度量,体现运行程序的内在规律.名字访问遵守作用域规则,而作用域以实体存活为前提7.5.1作用域C++的作用域有全局作用域、文件作用域、函数作用域、函数原型作用域、类作用域和局部作用域。作用域规则主要是针对程序文件而言,所以全局作用域就是文件作用域。函数作用域即不管名称在函数的什么地方声明,总是可以在函数的任何位置先使用该名称。只有标号是函数作用域的,设置标号即对标号名称进行声明,常以”goto标号;”的形式出现。函数原型作用域,是表明函数声明时的形参与上下文无关,如:
doublewidth;//其中的width并未重复定义voidarea(doublewidth,doublelength);length=0;//错:length无定义正因为如此,函数声明中形参可以省略。因为它与上下文没有任何关系。类作用域与名空间机制类似。局部作用域指在函数内部的动作序列描述中,依据各语句块甚至整个函数体范围内所定义的数据应遵循的数据访问规则。在局部作用域中,语句块往往是嵌套的,所以变量在其作用域并非一定可见,如果遇到更贴近的变量定义,则另一个外层同名定义将被暂时屏蔽。如://嵌套的局部作用域//=====================================#include<iostream>usingnamespacestd;//-------------------------------------voidfn(inty);intj=8;//j为全局作用域//-------------------------------------intmain(){intx=1;fn(x);}//----------------------//x作用域结束voidfn(inty){//y作用域开始
if(inti=1)//if语句块,i作用域开始
i=2*i;elsei=100;//if语句块结束,则i作用域结束
{intx=1;//x作用域开始
if(x>y)cout<<x<<endl;elsecout<<y<<endl;}//-------------------//x作用域结束
switch(inti=2){//switch语句块,i作用域开始
case1:cout<<i<<endl;}//switch语句块结束,则i作用域结束
i=3;//errorintsum=0;//sum作用域开始
for(inti=0;i<10;++i)//i作用域开始
sum+=i;//i作用域结束
intj=3;//fn函数块中,intj作用域开始
charch;//fn函数块中,charch作用域开始
{doublej;//本块中,doublej作用域开始
j=5;//虽赋整数于j,但仍然指doublej,非intj::j=6;//全局变量通过::操作可见,但局部intj不可见
ch='A';//只要本块中没有定义ch变量,则外块ch可见
}//doublej作用域结束
j=6.0;//intj可见}//====================================//j,ch,y,sum作用域结束7.5.2生命期生命期指一个实体产生后,存活时间的度量。静态局部数据的生命期并不与局部作用域一致,它的生命期一直延续到程序运行结束。另有一种动态生命期,是由new申请到内存空间后,该空间实体开始有效,一直到delete语句释放该内存空间。在动态生命期中,其有效的堆空间实体可能被跨函数地访问,因此,其作用域是整个程序范围的。如://动态生命期#include<iostream>//-------------------------------------int*fn(){int*ap=newint;//ap所指向的内存空间开始有效,可以访问了
returnap;}//------------------------------------intmain(){int*bp=fn();*bp=15;std::cout<<*bp<<"\n";delete[]bp;//bp所指即ap所指,此处使该内存空间无效7.6名空间名空间:解决名字冲突的方法.所有名字都有空间归属,在一定的空间中,名字是不允许冲突的.引用一个名字时,加上空间归属的前缀,就可以唯一确定该名字所对应的实体无前缀名字:很多时候,名字都是无前缀的,这是因为事先已经指定了默认名字空间.如果默认名空间在两个以上,则必须注意名字冲突的可能性C++的名称理解,肯定不能仅仅用名称的作用域规则来规范,名空间机制才是真正全面发挥作用的名称认定和作用域规则,它规定,一个名称必须在使用的域中明确声称其使用的“空间名”,才能在域中默认的使用该名称,就像使用
usingnamespacestd;一直在默认使用std标准库名一样。7.6.1名空间的概念C++的名空间机制,就是为了支持大规模程序的逻辑设计,排解名字冲突而产生的。程序设计语言的描述可以对应整个世界,世界上有许多重名,在不同的场合表达不同的意思,在程序里面,就是通过名空间来区分的。因为程序是跨文件的,所以对应的名空间也是跨文件的。7.6.2名空间的组织名空间的定义通过下列形式:
namespacename{//名称声明或定义}因为名空间总是凌驾于其他程序文件之上的,它是其他程序文件中的所有外部名称使用的规范描述,所以一般总是将名空间的定义放在头文件中。7.6.3组织模块一个模块的输入,是指其他模块提供的服务,模块的输出是提供给其他模块使用的服务。可以将包括许多程序文件在内的更大模块的名称集合,组织在一个头文件中,原先放在头文件中的各个声明,都可以放在名空间中而成为整个程序的模块结构层次中的一个。如有一个程序,由其函数调用关系可以将其划分为三个模块,模块1由文件1组成,模块2由文件2、3、4组成,模块3由文件5、6组成。如图7-5所示:图7-5函数调用关系
模块2
模块3mainf1f2f3f4
文件1
模块1文件2g1g2g3文件3h1h2h3文件4n1n2文件5k1k2k3k5k4文件6m1m2m3由图7-5能得到下图的程序文件组模块,共有三个模块:模块2模块3文件1f1f2f3f4f1f4f3f2m1k1h1g1,g2,g3模块1g1,g2,g3h1文件2g1g2g3g1g2g3文件3h1h2h3文件4n1n2h1n1n2模块2
模块3k1m1文件5k1k2k3k5k4文件6m1m2m3k1m1在软件设计人物完成后,便可以根据图例所示的三个模块为软件资源,再加上C++的系统资源,编写代码。7.6.4数据名冲突名空间解决模块名冲突问题远远不够,因为在模块中还有各种数据的往来,难免存在着交叉。数据的名空间规定更复杂,因为它们不但比模块数量更多,而且访问数据的权限并不是对每个程序员都一样的,常用的方法是使用“数据封装”来解决数据的名空间问题,也就是对象化编程的基本思想,在后面的类机制会详细讲述。7.6.5名空间的用法当自己要定义一个函数与标准库的名称发生冲突的时候,就不能简单的将标准库的所有名称一并默认,如定义一个:
intabs(inta){returna>0?a:-a;}这个时候,就可以选择一个版本使用,如://解决名字冲突//=====================================#include<iostream>//usingnamespacestd;//-------------------------------------intabs(inta){returna>0?a:-a;}//-------------------------------------intmain(){inta=abs(-5);intb=std::abs(-5);std::cout<<a<<std::endl<<b<<std::endl;}//====================================如果标准库中的某个名称用的很频繁,又可能会遇到标准库的名称与自己定义的名字冲突,就可以局部默认名空间的名称使用,如上述程序可以改写为://局部名空间默认//=====================================#include<iostream>usingstd::cout;usingstd::endl;//-------------------------------------intabs(inta){returna>0?a:-a;}//-------------------------------------intmain(){inta=abs(-5);intb=std::abs(-5);cout<<a<<endl<<b<<endl;}//====================================7.7预编译预编译:C++在正式编译前的准备工作,它包括文件的加盟、代码的取舍、字符的替代等操作文件加盟由include指令引导,代码取舍由ifdef或ifndef引导,字符替代功能在逐渐退化,因为C++语言本身完全可以胜任这项工作常用的预编译指令:包含指令#include条件指令#if、#elif、#else、#endif、#ifdef、#ifndef定义指令#define、#undef7.7.1#include指令include指令指示预编译将包含的头文件的内容附加到程序文件中,以参加编译。如果头文件是C++系统提供的,则用尖括号把头文件括起来,如果是自定义的头文件,则用双引号把头文件括起来。用户自定义的头文件一般放在源程序文件路径中7.7.2条件编译指令条件编译的作用是直接取舍程序语句和协调多个头文件。如在C++系统头文件中常有这样的编译指令:#ifdef_USE_OLD_RW_STL#include<oldstl\fstream.h>#else#include<stlport\fstream>#endif是为了兼容旧版C+
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年黑龙江省鹤岗市中小学教师招聘笔试试题及答案详解
- 2025年安徽省黄山市中小学教师招聘考试试题及答案详解
- 2026年阜新市清河门区街道办人员招聘笔试模拟试题及答案详解
- 2026年天津市西青区中小学教师招聘笔试参考试题及答案详解
- 2025年四平市铁东区街道办人员招聘考试试题及答案详解
- 2026年北京市顺义区街道办人员招聘笔试参考试题及答案详解
- 2026年咸阳市渭城区中小学教师招聘笔试参考试题及答案详解
- 2026年日照市岚山区中小学教师招聘笔试参考试题及答案详解
- 2026年朝阳市龙城区中小学教师招聘笔试参考试题及答案详解
- 2026年上海市长宁区街道办人员招聘考试参考试题及答案详解
- 象棋特级大师讲布局(定式与战理)
- 2026年中央一号文件解读:农村人居环境整治提升
- 和美乡村实施方案
- 医美安全生产管理制度
- 风机高处作业安全培训课件
- 用印流程规范制度
- 单位工会内控制度
- DB21-T 706-2025 森林经营技术规程
- 艺术培训机构教师聘用合同范本
- 2025年教师招聘考试教育综合基础知识备考全书
- 雨雾天气应急预案
评论
0/150
提交评论