第2章在较小范围内如何将C++增强C_第1页
第2章在较小范围内如何将C++增强C_第2页
第2章在较小范围内如何将C++增强C_第3页
第2章在较小范围内如何将C++增强C_第4页
第2章在较小范围内如何将C++增强C_第5页
已阅读5页,还剩58页未读 继续免费阅读

下载本文档

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

文档简介

面向对象程序设计(C++)OrientedObjectProgramming(C++)主讲:严冬梅第2章在较小范围内增强C第2章在较小范围内如何将C++增强C2.1数据类型2.2I/O流控制2.3运算2.4函数2.5引用2.6程序结构2.7其他附录2.1基本数据类型布尔类型bool字符型char数据类型整型int双精度型double浮点型(单精度型)float基本数据类型联合体union构造数据类型数组结构体struct枚举特殊类型

2.1.1

数据类型的分类空值类型void引用类型:reference指针类型:pointer双字符型wchar_t类class2.1数据类型2.1.2常用基本数据类型的取值范围类型长度取值范围char8位(1字节)-128~127unsignedchar8位(1字节)0~255short16位(2字节)-32768~32767unsignedshort16位(2字节)0~65535int(long)32位(4字节)-2147483648~2147483647unsignedint(long)32位(4字节)0~4294967295float32位(4字节)-3.4×1038~3.4×1038double64位(8字节)-1.8×10308~1.8×10308longdouble80位(10字节)-1.2×104932~1.2×1043922.1数据类型2.1.3

布尔型bool表示范围仅含整数0和1,也可以表示成true和false,相当于:

enumbool{false,true};因为条件表达式、逻辑运算的结果都是0或1,所以,相当大数量的表达式的值与布尔型对应。用任何非0整数给bool型变量赋值时,其值都是1,甚至非整数的其它类型,只要非0,其值也都是1。

boola=3,b=1;//a=1,b=1boolc=a+b,d=a-b;//c=1,d=02.1数据类型2.2.4const说明符在说明中根据不同情况,const的位置略有不同。使用const定义的常量,用来替代符号常量优点:不再是字符串,具有数据类型;在内存中占有空间;在执行语句中使用同变量一样,只是不能做左值。定义const[数据类型]常量名=初值;constdoublePI=3.1415926;constintSIZE=100;注意常量必须初始化;数据类型与变量的含义相同,缺省时为int。常量同样有全局和局部之分。常量可以定义在头文件中。2.2.1数据类型

指向常量的指针

const数据类型*指针名;

指针类型前加const,constint*p;

p是指针,是指向整型常量的指针,意味着*p不能改变,但是p可以改变。

即p=##;√*p=##;×

0067:f600100067:fd66变量p常量i,0067:f600constinti=10,j=20;constint*p=&i;p=&j;0067:f70020常量j0067:f7002.2.1数据类型指针常量数据类型*const指针名;

指针名前加const,int*constp;p是常量,是指向整型数据的指针常量,意味着p不能改变,但是*p可以改变。即p=##;×*p=##;√定义指针常量时必须初始化,初始化值是字符串常量的地址。0067:f60010变量i0067:f6000067:fd66常量pinti=10,j=20;int*constp=&i;*p=j;2020变量j0067:f7002.2.1数据类型

指向常量的指针常量

const数据类型*const指针名;

指针类型和指针名前均加const

constint*constp;

p是指针常量,是指向整型常量的指针常量,意味着p不能改变,*p也不能改变。即p=##;×*p=##;×0067:f600100067:f6000067:fd66常量p常量iconstinti=10;constint*constp=&i;2.2.1数据类型

用const修饰形式参数

voidfunc(conststructstudent*s){}

虽然以指针方式传递一个结构体指针,但对源数据不能做修改。用const修饰成员函数表示该成员函数不可以改变对象属性值。

intgetAge()const;2.2.2I/O流控制标准输入输出流C++中输入/输出流(一般叫iostreams或streams)提供了C的stdio.h库中的所有功能。输入/输出流用作将具有类型的对象转换成可读的正文,反之亦然。流能读写二进制数据。C++程序以四个预定义的流开始,它们是:

cin标准输入

cout标准输出

cerr标准错

clog缓冲的cerr2.2.2I/O流控制标准输入输出流标准输出流cout格式:cout<<输出序列<<输出序列<<……;输出序列有以下几种:

字符串原样输出

格式控制用来说明后面的输出数据的格式

变量或表达式输出变量或表达式值

cout<<“a=“<<a<<“,b=“<<b<<“,sum=“<<a+b;

输出结果:a=10,b=20,sum=302.2.2I/O流控制标准输入输出流标准输入流cin格式:cin>>变量1>>变量2>>……;

输入的数据以回车键结束

当连续输入多个变量时,输入数据可以用空白字符隔开,例如:cin>>a>>b;

输入的数据可以是1020↙输入的数据可以是10 20↙输入的数据可以是10↙20↙2.2.2I/O流控制注意1.输入一般不要求格式2.输入流能自动跳过空白字符chara,b,c;cin>>a>>b>>c;3.字符串输入避免溢出,可采取以下方法:

chararray[SIZE];cin.width(sizeof(array));cin>>array;//自动读取SIZE-1个字符

2.2.2I/O流控制使用控制符#include<iomanip>控制符描述dec置基数为10hex置基数为16oct置基数为8setfill(c)设填充字符为csetprecision(n)设显示小数精度为nsetw(n)设域宽为n个字符setiosflags(ios::fixed)固定的浮点表示setiosflags(ios::scientific)指数表示setiosflags(ios::left)左对齐setiosflags(ios::right)右对齐setiosflags(ios::skipws)忽略前导空白setiosflags(ios::showpoint)强制显示小数部分setiosflags(ios::showpos)强制显示正数的符号2.2.2I/O流控制2.4.2

使用控制符常用的格式控制通用的输出数据宽度setw(n)填充字符setfill(c)对齐方式setiosflags(ios::left)setiosflags(ios::right)整数进制dechexoct实数小数位数setprecision(n)setiosflags(ios::fixed)指数表示法setiosflags(ios::scientific)必须显示小数位setiosflags(ios::showpoint)字符串忽略前导空白setiosflags(ios::skipws)【例2.1】I/O流格式#include<iomanip>#include<iostream>usingnamespacestd;intmain(){inta=21;cout<<"dec:"<<a<<endl;//默认以十进制形式输出acout<<"hex:"<<hex<<a<<endl;//以十六进制形式输出acout<<"oct:"<<oct<<a<<endl;//以八进制形式输出achar*pt="China";//pt指向字符串”china”cout<<setw(10)<<pt<<endl;//输出字符串

cout<<setfill('*')<<setw(10)<<pt<<endl;//输出字符串

doublepi=22.0/7.0*100;//计算100pi值

cout<<setprecision(2)<<setiosflags(ios::scientific)<<setw(16)<<pi<<endl;cout<<setprecision(6)<<setw(16)<<pi<<endl;cout<<setiosflags(ios::fixed)<<setiosflags(ios::showpos)<<setprecision(6)<<setw(16)<<pi<<endl;return0;}2.2.3运算2.3.1new和delete

在任何一个变量使用前,都必须完成关于存储方面的有关安排:存放位置、占据多少存储单元。这个工作叫内存分配。编译时分配内存是静态内存分配运行时分配内存是动态内存分配堆内存——动态内存(在运行时申请内存)用户内存:代码区、全局数据区、栈区、堆。2.2.3运算2.3.1new和delete创建、销毁一变量

new

数据类型(初始值);

delete

指针名;int*p;p=newint;deletep;创建、销毁一数组

new

数据类型[长度];

delete[]指针名;int*p;p=newint[30];delete[]p;2.2.3运算说明

new分配堆内存,比malloc()更简练。

new的操作数为数据类型,它可以带初始化值表或单元个数。new返回一个具有操作数的数据类型的指针。

new和delete是C++专有的操作符,它们不用头文件声明。

delete类似于free(),释放堆内存。

由于堆对象的生存期是从创建对象到销毁或程序结束,因此,删除不再需要的堆对象是一个必须进行的工作。

(最重要的)new和delete在创建/释放类对象时可以自动进行对象的构造和销毁2.2.3运算【例2.2】创建、销毁一维数组#include<iostream>usingnamespacestd;intmain(){inti,n,*data;floatsum=0,avg;cout<<"请输入元素个数:";cin>>n;

data=newint[n];cout<<"请输入"<<n<<"个整数:";for(i=0;i<n;i++){cin>>data[i];sum+=data[i];}avg=sum/n;cout<<"元素总和为"<<sum<<",平均值为:"<<avg<<endl;delete[]data;return0;}2.2.3运算#include<iostream>usingnamespacestd;intmain(){int**p,i,j,m,n;cin>>m>>n;

p=newint*[m];for(i=0;i<m;i++){

p[i]=newint[n]; for(j=0;j<n;j++)cin>>p[i][j];}for(i=0;i<m;i++){for(j=0;j<n;j++)cout<<setw(5)<<*(*(p+i)+j);cout<<"\n";}

delete[]p;return0;}【例2.3】创建、销毁二维数组2.2.3运算

2.3.2

作用域限定运算符

::——表示全局变量

inti=10;intmain(){inti=5;::i+=10;cout<<”i=”<<i<<endl;……}i=202.2.4函数

2.4.1

内联函数什么是内联函数

内联函数也称内嵌函数

使用关键字inline说明的函数是内联函数

内联函数的作用相当于带参数的宏,就是将“函数调用”变成代码替换。

程序编译前,系统自动将内联函数进行代码替换(系统会自动优化代码)2.2.4函数使用内联函数的意义凡是有内联函数调用的地方就会有代码替换,即内联函数增加了代码空间,增加了编译时间采用一般函数调用,需要建立环境栈存储参数、返回地址等,并且产生程序执行转移,需要时间开销,因此,调用n次就会增加n次时间开销。编译只进行一次,但可运行多次,因此使用内联函数虽增加了编译时间,但减少了程序执行时间(函数调用开销)。2.2.4函数intmain(){charc;intisnumber(char);cout<<"Enteracharacter:";cin>>c;if(isnumber(c))cout<<"Youenteredadigit.";elsecout<<"Youenteredanon-digit.";return0;}intisnumber(charc){return(c>='0'&&c<='9')?1:0;}

对于isnumber这样简单的函数,使用函数调用的方法(特别是多次调用)将大大降低运行效率,可以采用if(c>='0'&&c<='9')表达式替换的方法。但是,手工替换很烦琐,最好让编译程序去做。内联函数是程序行的扩展,主要是解决程序的运行效率。2.2.4函数

内联函数的使用(1)在函数声明和定义的最前面加关键字inline

在函数声明时必须有inline,定义时可有可无。intmain(){charc;

inlineintisnumber(char);……}inlineintisnumber(charc)//或用intisnumber(charc){return(c>='0'&&c<='9')?1:0;}2.2.4函数

内联函数的使用(2)内联函数必须在调用之前声明或定义。因为内联函数的代码必须在被替换之前已经生成被替换的代码。inlineintisnumber(charc)

{return(c>='0'&&c<='9')?1:0;}

intmain()

{charc;

//inlineintisnumber(char);

……

}2.2.4函数内联函数的函数体限制内联函数中不能含有复杂的结构控制语句,否则,编译时将该函数视同普通函数那样产生函数调用代码。递归函数是不能被用来做内联函数的。内联函数只适合于只有1~5行的小函数。最适合使用内联函数:小函数、频繁调用2.2.4函数2.函数重载

使用重载函数的必要性

在不同类型上作相同运算而又用相同名字的情况,称为重载。intadd(intx,inty)

{inttemp;temp=x+y;returntemp;

}

doubleadd(doublex,doubley)

{doubletemp;temp=x+y;returntemp;

}

intmain()

{inta=4,b=5;doublex=12.5,y=75.75;

cout<<add(a,b)<<"\t"<<add(x,y)<<endl;return0;

}运行结果为:

9 88.252.2.4函数

使用重载函数的必要性使用不同数目的参数#include<iostream>usingnamespacestd;

intmul(intx,inty)

{inttemp;temp=x*y;returntemp;}

intmul(intx,inty,intz)

{inttemp;temp=x*y*z;returntemp;}

intmain()

{inta=5,b=10,c=20;

cout<<mul(a,b)<<"\n"<<mul(a,b,c)<<endl;return0;

}运行结果为:

50

10002.2.4函数使用说明(1)重载函数仅仅是返回类型不同是不够的

重载函数至少在参数个数、参数类型或参数顺序上有所不同(2)不能用typedef定义的类型名来区分重载函数声明中的参数(3)重载函数应该具有相同的功能

通过名字粉碎来区分重载函数2.2.4函数

匹配重载函数的顺序只要参数表互不相同,C++就会根据所给参数调用正确的函数。(1)寻找一个严格的匹配(2)通过内部转换寻求一个匹配(3)通过用户定义的转换寻求一个匹配2.2.4函数3.默认参数默认参数的目的调用某函数时传递的参数经常是同一值,则可使用默认参数,即调用函数时不给出实参,而是直接取默认值。默认参数的声明若有函数声明,则在声明中默认参数,不能写在定义中;若无函数声明,则在定义中默认参数。2.2.4函数

默认参数的顺序规定默认参数应从右至左逐渐定义。

voidfun(inta=1,intb,intc=3);×voidfun(inta,intb=1,intc=3);√当调用参数时只能向左匹配参数(靠右面的默认参数先有效)。

voidfun(inta=1,intb=2,intc=3);

fun(5,10);->a=5,b=10,c=32.2.4函数默认参数与函数重载默认参数可以将一系列重载函数合成一个为函数,但由于必须从右至左定义,并向左匹配参数,因此它没有重载函数灵活,而且数据类型也有限制。intInitDate(inty=1972,intm=3,intd=26);默认值的限定默认值可为全局变量、全局常量和函数,即不能是局部变量。2.2.5引用1.引用概念的导入2.引用的定义3.用引用传递函数参数4.返回引用与返回值5.函数调用作为左值6.用const限定引用7.堆中变量的引用1.引用概念的导入参数传递的传值方式在函数域中为参数重新分配内存,而把实参的数值传递到新分配的内存中。它的优点是有效避免函数的副作用。问题如果要求改变实参的值,怎么办呢?如果实参是一个复杂的对象,重新分配内存会引起程序执行效率大大下降,怎么办呢?有一种导出型数据类型—引用(reference)。引用就是给另一个变量或对象起一个别名(alias)。2.引用的定义数据类型&引用名=初始值;引用在声明时必须初始化inti;int&j=i;对引用的改变就是对引用变量的改变。intmain(){intintOne;int&rInt=intOne;intOne=5;cout<<"intOne:"<<intOne<<endl;cout<<"rInt:"<<rInt<<endl;rInt=7;cout<<"intOne:"<<intOne<<endl;cout<<"rInt:"<<rInt<<endl;return0;}intOne:5rInt:5intOne:7rInt:72.引用的定义数据类型&引用名=初始值;int&j=i;

引用不是值,不占内存。对引用取地址,返回的是引用目标变量的地址。intmain(){intintOne;int&rInt=intOne;intOne=5;cout<<"intOne:"<<intOne<<endl;cout<<"rInt:"<<rInt<<endl;cout<<"&intOne:"<<&intOne<<endl;cout<<"&rInt:"<<&rInt<<endl;return0;}intOne:5rInt:5&intOne:0018FF44&rInt:0018FF442.引用的定义数据类型&引用名=初始值;int&j=i;引用永远维系在一个目标上intmain(){intintOne;int&rInt=intOne;intOne=5;cout<<"intOne:"<<intOne<<endl;cout<<"rInt:"<<rInt<<endl;cout<<"&intOne:"<<&intOne<<endl;cout<<"&rInt:"<<&rInt<<endl;intintTwo=8;rInt=intTwo;cout<<"intOne:"<<intOne<<endl;cout<<"intTwo:"<<intTwo<<endl;cout<<"rInt:"<<rInt<<endl;cout<<"&intOne:"<<&intOne<<endl;cout<<"&intTwo:"<<&intTwo<<endl;cout<<"&rInt:"<<&rInt<<endl;}intOne:5rInt:5&intOne:0018FF44&rInt:0018FF44intOne:8intTwo:8rInt:8&intOne:0018FF44&intTwo:0018FF3C&rInt:0018FF442.引用的定义数据类型&引用名=初始值;int&j=i;初始化目标类型必须与引用的数据类型一致或可以转化成引用的数据类型。inti;int&j=i;int&j=1;double&rr=1;doubletemp;temp=double(1);double&rr=temp;

指针变量的引用int*a;int*&p=a;//p是int*的引用,p是a的别名p=&i;a=&i;2.引用的定义数据类型&引用名=初始值;int&j=i;不能引用void型(包括指针)void&i;×void*&p=q;×不能建立引用数组inta[10];int&b[10]=a;×

数组占用连续的内存空间,而引用不占内存没有引用的引用,也没有引用的指针inta;int&ra=a;int&rr=ra;×int*p=ra;×

引用不占内存,不属于数据类型,所以无法引用,也无法被指向3.用引用传递函数参数用引用可以实现C中地址传送的功能,而且比地址(指针)传递更简单和易于理解。intmain(){inta=5,b=10;voidswap(int&,int&);swap(a,b);printf(“a=%d,b=%d\n”,a,b);return0;}voidswap(int&x,int&y){intt;t=x;x=y;y=t;}main()swap()5a:10b:t:5105x:a:y:b:a:b:3.用引用传递函数参数注意重载函数voidfn(int){…}voidfn(int&){…}intmain(){inta=10;fn(a);//产生歧义,系统无法确定调用哪个fn()}3.用引用传递函数参数引用与指针一样,可以返回多个值boolFactor(intn,int&rSquared,int&rCubed){if(n>20||n<0)returnfalse;rSquared=n*n;rCubed=n*n*n;returntrue;}intmain(){intnumber,squared,cubed;boolerror;cout<<"Enteranumber(0~20):";cin>>number;error=Factor(number,squared,cubed);if(!error)cout<<"Errorencountered!\n";else{cout<<"Number:"<<number<<endl;cout<<"Squared:"<<squared<<endl;cout<<"Cubed:"<<cubed<<endl;}return0;}Enteranumber(0~20):15Number:15Squared:225Cubed:3375Enteranumber(0~20):45Errorencountered!4.返回引用与返回值函数返回值,生成一个副本函数返回引用,不生成副本floattemp;floatfn1(floatr){temp=r*r*3.14;returntemp;}float&fn2(floatr){temp=r*r*3.14;returntemp;}intmain(){floata=fn1(5.0);//1:变量接收返回值float&b=fn1(5.0);//2:引用接收返回值

floatc=fn2(5.0);//3:变量接收返回引用float&d=fn2(5.0);//4:引用接收返引用cout<<a<<endl;cout<<b<<endl;cout<<c<<endl;cout<<d<<endl;return0;}4.返回引用与返回值1:变量接收返回值(正确,产生副本)floatfn1(floatr){temp=r*r*3.14;returntemp;}floata=fn1(5.0);main()fn1()78.5a:5.0r:78.5temp:78.5栈全局数据临时:4.返回引用与返回值2:引用接收返回值(隐含错误)floatfn1(floatr){temp=r*r*3.14;returntemp;}float&b=fn1(5.0);main()fn1()b:5.0r:78.5temp:78.5栈全局数据临时:4.返回引用与返回值3:变量接收返回引用(正确,不产生副本)float&fn2(floatr){temp=r*r*3.14;returntemp;}floatc=fn2(5.0);main()fn2()78.5c:5.0r:temp:78.5栈全局数据4.返回引用与返回值4:引用接收返引用(不产生副本,容易错误,temp为自动变量时出错)float&fn2(floatr){temp=r*r*3.14;returntemp;}float&d=fn2(5.0);main()fn2()b:5.0r:temp:78.5栈全局数据5.函数调用作为左值函数返回值是引用可以使函数成为左值float&fun(intindex,floata[]){float&r=a[index];returnr;}floattest[]={3.5,5.4,5.5};fun(1,test)=4.5;<=>test[1]=4.5与指针一样,当函数返回引用时,注意避免产生悬挂引用。5.函数调用作为左值普通写法intarray[6][4]={{60,80,90,75},{75,85,65,77},{80,88,90,98},{89,100,78,81},{62,68,69,75},{85,85,77,91}};intgetLevel(intgrade[],intsize){intsum=0;for(inti=0;i<size;i++)sum+=grade[i];sum/=size;//平均分

if(sum>=80)return1;//typeAstudentelsereturn0;//typeBstudent}intmain(){inttypeA=0,typeB=0;intstudent=6;intgradesize=4;for(inti=0;i<student;i++)//处理所有的学生

if(getLevel(array[i],gradesize))typeA++;elsetypeB++;cout<<"numberoftypeAis"<<typeA<<endl;cout<<"numberoftypeBis"<<typeB<<endl;return0;}5.函数调用作为左值函数成为左值intarray[6][4]={{60,80,90,75},{75,85,65,77},{80,88,90,98},{89,100,78,81},{62,68,69,75},{85,85,77,91}};int&level(intgrade[],intsize,int&tA,int&tB){intsum=0;for(inti=0;i<size;i++)sum+=grade[i];sum/=size;//平均分

if(sum>=80)returntA;//typeAstudentelsereturntB;//typeBstudent}intmain(){inttypeA=0,typeB=0;intstudent=6;intgradesize=4;for(inti=0;i<student;i++)//处理所有的学生

level(array[i],gradesize,typeA,typeB)++;//函数作左值cout<<"numberoftypeAis"<<typeA<<endl;cout<<"numberoftypeBis"<<typeB<<endl;return0;}6.用const限定引用当函数需传递的实参是很大的数据类型时(数组、结构体),参数传递采用指针或引用。但是,采用指针和引用就存在修改实参的风险。因此,用const来限定引用或指针作为函数的形参,以保证实参不被修改。voidfn(constint&a);voidfn(constint*p);6.用const限定引用C++不区分变量的const引用还是常量的const引用,因为引用总是const的,不允许对引用赋值不需要constdoubleconst&a=1;只需constdouble&a=1;a=2;×对比constdoubleconst*p=&i;p=&j;×7.堆中变量的引用不能直接引用堆空间,必须借助指针int*p=newint;if(p==NUULL){cout<<"Nomemory!\n";return1;}int&r=*p;int*p=newint[30];if(p==NUULL){cout<<"Nomemory!\n";return1;}int*&r=p;用堆空间初始化引用,既可以用指针释放,也可以用引用释放堆空间。deletep;<==>delete&r;2.2.6程序结构程序=算法+数据结构—算法与数据结构是一个整体

封装和信息隐藏是面向对象的基本要素。算法总是离不开数据结构,算法含有对数据结构的访问,算法只能适用于特定数据结构。程序={(类)}={(算法+数据结构)}—数据结构与算法分离。

软件系统的规模越来越大,复杂性不断增长,以致不得不对“关键数据结构”重新评价。

数据结构的主要欠缺是应用

温馨提示

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

评论

0/150

提交评论