- 246.50 KB
- 2022-07-30 发布
- 1、本文档由用户上传,淘文库整理发布,可阅读全部内容。
- 2、本文档内容版权归属内容提供方,所产生的收益全部归内容提供方所有。如果您对本文有版权争议,请立即联系网站客服。
- 3、本文档由用户上传,本站不保证质量和数量令人满意,可能有诸多瑕疵,付费之前,请仔细阅读内容确认后进行付费下载。
- 网站客服QQ:403074932
第1章面向对象分析1.1结构化技术与面向对象技术1.结构化技术:以“过程”为基础,将模型化的功能过程化。2.人类认知世界的基本方式是:(1)分类认知(2)整体认知(3)推理衍生面向对象技术的特点:(1)软件复用(2)可维护性“每个组件在做什么(功能问题)/与系统其他组件有什么关系"(3)在现有对象基础上构件应用程序(4)纯语言1.3面向对象技术基础分析1.对象(Object)对象状态:一个对象在生命周期过程中的一个状态。对象状态可以用静态属性值来表示。2.类(Class)类是面向对象语言必需提供的用户定义的数据类型,它将具有相同状态、操作和访问机制的多个对象抽象成为一个对象类。类给出了属于该类的全部对象的抽象定义,而对象则是符合这种定义的一个实体。所以,一个对象又称作类的一个实例(instance)。3.数据抽象(DataAbstraction)数据抽象是从大量的数据中提取出有意义的信息,以便进一步处理。4.封装性(Encapsulation)封装是面向对象方法的一个重要原则。它有两个涵义:把对象的全部属性和全部服务结合在一起,形成一个不可分割的独立单位(对象)。也称作“信息隐蔽”(InformationHiding),即尽可能隐蔽对象的内部细节,对外形成一个边界(或者说形成一道屏障),只保留有限的对外接口使之与外部发生联系。这主要是指对象的外部不能直接地存取对象地属性,只能通过几个允许外部使用地服务与对象发生联系。数据抽象和封装的优点(1)保护内部数据的安全性(2)稳定的接口有利于变化系统的扩展升级5.继承性(Inheritance)57\n继承是面向对象语言的另一特性。类与类之间可以组成继承层次,一个类的定义(子类,派生类)可以定义在另一个已定义类(父类,基类)的基础上。子类可以继承父类中的属性和操作,也可以定义自己的属性和操作。继承性的特点由下而上(抽象继承):提取多个类(子类)的共同特征,泛化和抽象为一个更具普遍意义的类(父类)。由上而下(派生继承):由一个类(基类)的特征表示更加细化和特化,生成更特殊的类(派生类)。根类:没有基类(父类)的特殊类。6.多态性(Polymorphism)对象的多态性是类的同名方法在不同的情况下具体实现不同。通常有以下两层含义:对象提供形式不同,但功能相似的服务指在一般类中定义的属性或操作被特殊类继承之后,可以具有不同的数据类型或表现出不同的行为。这使得同一个属性或操作名在一般类及其各个特殊类中具有不同的语义。第2章面向对象设计2.体系结构框架1.系统体系结构的类型(1)批处理型:对整个输入集进行数据转换。(2)连续型:随着输入的实时变化,实时进行数据转换。(3)交互型:由外部的交互控制应用。(4)事务型:以内关于以存储和更新数据为中心,支持并发访问。(5)基于规则型:由一定的强制性规则支配应用。(6)模拟型:应用模拟显示世界对象。(7)实时型:以严格的定时约束控制应用第3章C++基础知识C++源文件的扩展名为.CPP。3.2.2编译将编辑好的C++源程序通过编译器转换为目标文件(OBJ文件)。即生成该源文件的目标代码。57\n3.2.3链接将用户程序生成的多个目标代码文件(.obj)和系统提供的库文件(.lib)中的某些代码连接在一起,生成一个可执行文件(.exe)。3.2.4执行把生成的可执行文件运行,在屏幕上显示运行结果。用户可以根据运行结果来判断程序是否出错。3.3C++的词法与规则3.3.1C++的字符集数字:0,1,2,3,4,5,6,7,8,9。小写字母:a,b,…,y,z。大写字母:A,B,…,Y,Z。运算符:+,-,*,/,%,<,<=,=,>=,>,!=,==,<<,>>,&,|,&&,‖,∧,~,(),[],{},->,•,!,?,?:,,,;,”,#。特殊字符:(连字符或下划线)。不可印出字符:空白格(包括空格、换行和制表符)。1.标识符标识符是对实体定义的一种定义符,由字母或下划线(或连字符)开头、后面跟字母或数字或下划线(或空串)组成的字符序列,一般有效长度是8个字符(而ANSIC标准规定31个字符),用来标识用户定义的常量名、变量名、函数名、文件名、数组名、和数据类型名和程序等。2.关键字:关键字是具有特定含义,作为专用定义符的单词,不允许另作它用。autobreakcasecharclassconstcontinuedefaultdoddefaultdeletedoubleelseenumexplicitexternfloatforfriendgotoifinlineintlongmutablenewoperatorprivateprotectedpublicregisterreturnshortsignedsizeofstaticstatic_caststructswitchthistypedefunionunsignedVirtualvoidwhile57\nC++语言的分隔符主要是:空格、制表和换行符。例:一个简单的C++程序。57#includevoidmain(){cout<<”ThisismyfirstC++program.\n”;//输出ThisismyfirstC++program./*输出ThisismyfirstC++program.*/}3.4C++程序的构成C++语言程序由以下基本部分组成。1.函数2.预处理命令预处理命令以位于行首的符号“#”开始,C++提供的预处理有宏定义命令、文件包含命令和条件编译命令三种。3.程序语句如下是程序控制语句类型:if() else条件语句for() 循环语句while() 循环语句do while()循环语句continue结束本次循环语句break中止循环式switch语句switch多分支选择语句57\ngoto转移语句return从函数返回语句(5)函数调用语句函数调用语句是由一次函数调用加一个分号而构成的一个语句。例如:max(x,y);(6)空语句空语句:;即只有分号“;”的语句,什么也不做。3.5堆与动态创建运算符3.5.1堆对象1.C++程序的内存布局(通常分为四个区)(1)全局数据区(dataarea):存放全局变量、静态数据、常量。(2)代码区(codearea):存放类成员函数、其他函数代码。(3)栈区(stackarea):存放局部变量、函数参数、返回数据、返回地址。(4)堆区(heaparea):自由存储区。2.堆对象(变量)堆对象(变量)是在程序运行时根据需要随时可以被创建或删除的对象(变量),当创建堆对象(变量)时,堆中的一个存储单元从未分配状态变为已分配状态,当删除堆对象(变量)时,存储单元从分配状态又变为未分配状态,可供其他动态数据使用。3.5.2new和delete与对基本数据类型操作一样,new和delete算符可以用于创建和删除堆对象。newT(初始值);//创建一个T类型对象,返回值为对象首地址newT[E];//创建一个T类型对象数组,返回值为数组首地址delete指针变量;//删除一个指针变量所指的对象delete[]指针变量;删除一个指针变量所指的对象数组注意:其中T是类型,E是算术表达式。例1:new与delete运算符例2:堆对象数组例3:函数中的new与delete运算符57\n3.5.3new和delete注意事项new运算返回指定类型的指针,如果分配内存失败(如没有足够的内存空间),则返回0;在程序中对应于每次使用运算符new,都应该相应地使用运算符delete来释放申请的内存。并且对应于每个运算符new,只能调用一次delete来释放内存,否则有可能导致系统崩溃。delete运算必须删除用new动态分配的有效指针;否则回带来严重问题,如系统崩溃。new和delete最好成对使用,以避免出现异常。delete运算释放数组堆对象,必须注明delete了数组有多少个元素。(见例2:堆对象数组)delete只是删除动态内存单元,并不会删除指针本身。对空指针调用delete是安全的。C++语言有两个库函数:malloc()与free()。这两个函数也是实现动态内存分配作用的,其功能分别与运算符new和delete相似。但是最好不要将库函数和运算符混合使用,否则可能导致系统崩溃。3.6引用、数组与指针3.6.1.引用标识符&C++中用&可派生出一个引用类型,即产生同一变量的另一个名字。引用在C++中非常普遍,主要用途是为用户定义类型指定操作,还可用于函数参数的传递,对引用型参数的操作,就是对实际参数的操作。例如:main(){intnum=50;int&ref=num;ref+=10;printf("num=%d",num);}3.6.2引用的特点课本(P183)(1)可以说明任何类型的引用,引用可以使用任何合法变量名。(2)引用不是变量,说明时必须初始化,并且以后不可以更改为其他变量的引用。(3)引用不是值,不占存储空间,说明引用时,目标的存储状态不会改变。所以,引用只有说明,没有定义。(4)引用仅仅在说明时带“&”符号,此后的引用的用法与变量完全相同。(5)引用最好做函数形参,其作用效果与指针做函数形参相似,都可以带回(6)数运算后的结果值;但在函数体内部,引用的用法与变量完全相同,所(7)比指针简单易懂。(见例4:引用类型和指针类型做函数形参)57\n3.6.3const和volatileconst和volatile是类型修饰符。在变量说明语句中,const用于冻结一个变量,使其在程序中不能被修改。在用const说明变量时,必须对该变量进行初始化。用volatile修饰的变量,虽然在一段程序中没有明显被改动,单这个变量的值也会因为程序外部的原因(如中断等)而改变。3.6.4数组2.一维数组课本P1023.一维数组的初始化书上P103笔记/书P106那段话4.数组的赋值用“=”赋值:与数组元素的初始化不同,在给数组元素进行赋值时,必须逐一赋值。例如:对于下述的数组初始化:inta[3]={1,2,3};其等价的赋值形式如下:inta[3];a[0]=1;a[1]=2;a[2]=3;注意:若要在数组之间进行赋值,也只能一个一个元素地赋值。例如:将上述数组a的值赋给另一个同样大小的数组b,可以利用下面的循环完成赋值操作:for(i=0;i<3;i++)b[i]=a[i];用流命令赋值其语法格式为:cin>>数组名;或cin>>数组名[下标];例如:对一个大小为5的字符型数组a赋值,可以用下列两种方式:chara[5];cin>>a;用scanf()函数其语法格式为:scanf(“类型标识”,数组名);或scanf(“类型标识”,数组元素地址);用C++库函数中的strcpy()函数(字符串拷贝函数)其常见语法格式为:strcpy(数组名,字符串);//将一个字符串赋值到一个字符数组中例如:charstr1[10];strcpy(str1,”hello”);注意,此例不能写为:str1=”hello”;//不合法另一种常见的语法格式为:strcpy(数组名1,数组名2);//将数组2中的字符串赋值到数组1中例如:strcyp(str1,str2);57\n注意,上例不能写为:str1=str2;//不合法5.数组越界在给数组元素赋值或对数组元素进行引用时,一定要注意下标的值不要超过数组的范围,否则会产生数组越界问题。因为当数组下标越界时,编译器并不认为它是一个错误,但这往往会带来非常严重的后果。例如:定义了一个整型数组a:inta[10];数组a的合法下标为0 9。如果程序要求给a[10]赋值,将可能导致程序出错,甚至系统崩溃。常用下面的式子确定数组的大小,预防数组越界情况的发生。假定对于一个整型数组a,它的大小为:sizeof(a)/sizeof(int)sizeof(a)表示求数组a在内存中所占字节数,sizeof(int)表示求整型数据在内存中所占字节数。使用上面这个式子,可以使数组大小计算在16位机器和32位机器之间移植。8.数组与函数数组也可以作为函数参数,将数组中数据传送到另一个函数中。传递可以采用两种方法:(1)数组元素作为函数的参数(2)数组名作为函数的参数当用数组名作为函数的实参和形参时,传递的是数组的地址。这时实参数组和形参数组应该分别在它们所在的函数中定义。此时采取的不是“值传送”方式,而是“地址传送”方式,即把实参数组的起始地址传送给形参数组,这样形参数组就和实参数组共占同一段内存单元,当形参值发生变化时,实参值也发生变化。此时应该注意:(1)实参数组与形参数组类型要一致。(2)形参数组的长度不要超过实参数组的长度。实参数组必须定义为具有确定长度的数组,而形参数组可以不定义长度,只在数组名后跟一个空的方括号,同时在被调用的函数中另设一个参数用来传递元素的个数。(3)可以在被调用函数中采用降维处理,即用单重循环来遍历二维数组中的所有元素。此时调用函数中的数组不要用数组名表示,而要用第一个元素的地址表示。3.6.5指针课本P1701.指针是一类特殊的变量(对象),存储的是程序中另一个对象在内存中的地址。57\n2.定义格式:<数据类型>*<指针变量(对象)名>;3.指针初始化指针对象可以被一个相同类型的对象初始化;例如:inti;int*p=&i;同一类型的指针之间可以相互赋值;例如:inti,*p1,*p2;p1=&i;p2=p1;通过直接分配内存地址初始化;例如:int*p1;p1=newint;直接赋值空指针;例如:int*p1=NULL,*p2=0;通用指针赋值;例如:void*p1;float*p2;p1=p2;p2=(float*)p1;4.C++中有两个有关指针的特别运算符:&运算符:为取地址运算符,&x的值为x的地址。*运算符:指针运算符,或指向运算符,也称间接运算符,*p代表p所指向的变量。在指针变量的定义和指针变量的引用中都有*p。但引用指针时的*p与定义指针变量时用的*p是有区别的,它们形式上有些相似,而含义是不同的。注意区分下面三种表示方法所具有的不同意义。例如,有一个指针px,px--指针变量,它的内容是地址量。*px--指针的目标变量,它的内容是数据。&px--指针变量占用的存储区域的地址。5.指针运算指针运算的实质是地址的计算,它只能进行算术运算、关系运算和赋值运算。指针的算术运算指针与整数的加减运算:(px+n,px-n)指针加1、减1运算:(px++,++px,px--,--px)指针的相减运算:(px-py)指针的关系运算在两个指向相同类型变量的指针之间可以进行各种关系运算。两指针之间的关系运算表示它们指向的地址位置之间的关系。(p1==p2)结果为1表示相同类型指针变量p1,p2指向同一地址空间;结果为0反之;(p1>p2)结果为1表示相同类型指针变量p1的地址在p2的地址的前面;结果为0反之;(P==0)和(P!=0)判断指针是否为空;57\n注意:指向不同数据类型的指针之间的关系运算是没有意义的,指针与非0整数之间的关系运算也是没有意义的。函数指针(课本P178)函数指针就是指向函数的指针。定义函数指针的语法格式为:<数据类型>(*函数指针名)(<参数表>);其中,数据类型是指函数指针所指向函数的返回值的类型,参数表中指明该函数指针所指向函数的形参类型和个数。例如:int(*p)(int,int);就定义了一个函数指针p,它指向一个返回整型值,有两个整型参数的函数。在定义了指向函数的指针变量后,在使用此函数指针之前,必须先给它赋值,使它指向一个函数的入口地址。由于函数名是函数在内存中的首地址,因此可以赋给函数指针变量。赋值的一般语法格式为:函数指针名=函数名;例如,对上面刚定义的函数指针p,可以给它赋值如下:p=func1;其中,函数名所代表的函数必须使一个已经定义过的,和函数指针具有相同返回类型的函数。并且等号后面只需写函数名而不要写参数,当函数指针指向某函数以后,可以用下列形式调用函数:(*指针变量)(实参表列)例如:(*p)(a,b),它相当于funl(a,b)。注意:指针的运算在这里是无意义的。因为指针指向函数的首地址。当用指针调用函数时,程序是从指针所指向的位置开始按程序执行,若进行指针运算,程序的执行就不是从函数的开始位置执行,这就会造成错误。与定义一般变量指针数组一样,C++语言中也可以定义具有特定返回类型和特定参数类型的函数指针数组。函数指针数组也可以是多维的,不过在实际编程中多只用到一维函数指针数组。定义它的语法格式如下:<数据类型>(*函数指针名[常量表达式])(参数表);例如:int(*p[5])(int,int);就定义了一个含有5个元素的函数指针数组,其中的每个元素都是一个指向函数的指针,且指向的函数都是返回值类型为整型,带两个整型参数的函数。3.6.6常引用与常指针57\n1.用const修饰说明引用为常引用。常引用所引用的对象不能被更新。常引用的说明形式如下:const<类型说明符>&<引用名>;例如:inta=10;constint&n=a;其中,n是一个常引用,它所引用的对象不会被更新。如果出现:n=123;则是非法的。常引用作函数形参,在函数中不能更新它所引用的对象,因此对应的实参不会被破坏。2.用const修饰定义指针为常指针。常指针的定义有两种:<类型>*const<指针变量名>;//表示常量指针,const修饰的是指针变量,该指针变量本身不能更新其中存储的地址值,但指针所指向的地址中所存储的值可以更新。const<类型>*<指针变量名>;//表示指针常量,const修饰的是<类型>*,该指针变量可以更新其中存储的地址值,但指针所指向的地址中所存储的值不能更新。(见例6:常量指针与指针常量)3.7函数基础扩展一个函数定义中的<参数表>可以被省略,表明该函数为无参函数,若<参数表>用void取代,则也表明是无参函数,若<参数表>不为空,同时又不是保留字void,则称为带参函数。*函数定义说明注意:在一个函数体内允许有一个或多个return语句,一旦执行到其中某一个return语句时,return后面的语句就不再执行,直接返回调用位置继续向下执行。C++中不允许函数定义嵌套,即在函数定义中再定义一个函数是非法的。一个函数只能定义在别的函数的外部,函数定义之间都是平行的,互相独立的。常见的函数调用方式有下列两种:方式一:将函数调用作为一条表达式语句使用,只要求函数完成一定的操作,而不使用其返回值。若函数调用带有返回值,则这个值将会自动丢失。例如:max(3,5);方式二:对于具有返回值的函数来说,把函数调用语句看作语句一部分,使用函数的返回值参与相应的运算或执行相应的操作。例如:57inta=max(3,5);inta=max(3,5)+1;cout<intmax(inta,intb,intc){intt;t=a;if(b>t)t=b;if(c>t)t=c;returnt;}5757\n3.函数调用时的参数传递(1)按值传递(2)地址传递(3)引用传递:引用传递方式是在函数定义时在形参前面加上引用运算符“&”。3.7.4特殊函数1.内联函数(课本P137)内联扩展(inlineexpansion)简称为内联(inline),内联函数也称为内嵌函数。当在一个函数的定义或声明前加上关键字inline则就把该函数定义为内联函数,它主要是解决程序的运行效率。内联函数可以在一开始仅定义或声明一次,但必须在函数被调用之前定义或声明。内联函数中不能含有任何循环以及switch和goto语句;内联函数中不能说明数组;递归函数(自己调用自己的函数)不能定义为内联函数。2.重载函数函数重载又称为函数的多态性,是指同一个函数名对应着多个不同的函数。所谓“不同”是指这些函数的形参表必须互不相同,或者是形参的个数不同,或者是形参的类型不同,或者是两者都不相同,否则将无法实现函数重载。例如,下面是合法的重载函数:intfunc1(int,int);intfunc1(int);doublefunc1(int,long);doublefunc1(long);重载函数的类型,即函数的返回类型可以相同,也可以不同。但如果仅仅是返回类型不同而函数名相同、形参表也相同,则是不合法的,编译器会报“语法错误”。除形参列表外都相同的情况,编译器不认为是重载函数,只认为是对同一个函数原型的多次声明。在调用一个重载函数func1()时,编译器必须判断函数名func1到底是指哪个函数。它是通过编译器,根据实参的个数和类型对所有func1()函数的形参一一进行比较,从而调用一个最匹配的函数。注意:函数名必须相同/函数返回值可以不同/参数列表必须不同(参数类型或参数个数不同)3.带默认形参值的函数当一个函数既有定义又有声明时,形参的默认值必须在声明中指定,而不能放在定义中指定。只有当函数没有声明时,才可以在函数定义中指定形参的默认值。默认值的定义必须遵守从右到左的顺序,如果某个形参没有默认值,则它左边的参数就不能有默认值。例如:voidfunc1(inta,doubleb=3.75,intc=3);//合法voidfunc1(inta=1,doubleb,intc=3);//不合法在进行函数调用时,实参与形参按从左到右的顺序进行匹配,当实参的数目少于形参时,如果对应位置形参又没有设定默认值,就会产生编译错误;如果设定了默认值,编译器将为那些没有对应实参的形参取默认值。57\n注意:形参的默认值可以是全局常量、全局变量、表达式、函数调用,但不能为局部变量。4.函数的嵌套调用由前述可知,C++函数不能嵌套定义,即一个函数不能在另一个函数体中进行定义。但在使用时,允许嵌套调用,即在调用一个函数的过程中又调用另一个函数。例如:57func1(inta,floatb){floatc;c=func2(b-1,b+1);}intfunc2(floatx,floaty){函数体}func1和func2是分别独立定义的函数,互不从属。575.递归函数(课本P140)一个函数直接或间接地调用自身,这种现象就是函数的递归调用。递归调用有两种方式:直接递归调用:直接递归调用即在一个函数中调用自身;间接递归调用:即在一个函数中调用了其他函数,而在该其他函数中又调用了本函数。利用函数的递归调用,可将一个复杂问题分解为一个相对简单且可直接求解的子问题(“递推”阶段);然后将这个子问题的结果逐层进行回代求值,最终求得原来复杂问题的解(“回归”阶段)。57#include"iostream.h"longf(intn){if(n<0){cout<<“error!“<