版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
C++对C的基本扩充C++对C的扩充C++包含了C的所有成分。C++在C的基础上增加了一些新的语言机制:更好地支持过程式编程,提高与类型相关的安全性。(基本扩充)支持面向对象编程。支持泛型编程。......C++对C的基本扩充局部变量的定义位置:C++允许局部变量的定义可以夹插在语句中。变量的使用点与定义点相距不至于太远,便于理解与维护。常量定义:#definePI3.1416constdoublePI=3.1416;//C++扩充的,便于编译时进行类型检查变量初始化方法:intx=0;intx(0);//C++扩充的,与对象的初始化保持一致,去除=的歧义条件的满足与不满足0表示不满足,非0表示满足bool类型:true表示满足;false表示不满足(C++扩充的,便于理解)注释/*...........*///......(C++扩充的,便于单行注释的书写)C++对C的基本扩充内联(inline)函数:编译时把函数体嵌入到函数的调用点,提高对小函数的调用效率。函数的参数可以指定默认值:调用时一些实参可以缺省,方便了使用。名空间(namespace):使得不同模块可以有同名的全局实体。标准库:保留了C的标准库,但头文件名从*.h改成c*,另外,库中的全局实体定义在名空间std中。动态内存分配:增加了新的操作符new与delete。引用类型:具有指针的一些作用,但比指针更安全函数名重载:在同一个作用域中,多个函数可以取相同的名字匿名函数(λ表达式):把函数定义和使用合而为一基于范围的for语句:防止数组下标越界类型自动判断auto:定义变量时自动识别变量的类型C++对C的基本扩充输入/输出intx;doubley;scanf("%d%lf",&x,&y);//输入cin>>x>>y;//C++扩充,#include<iostream>printf("%d,%f\n",x,y);//输出cout<<x<<y;//C++扩充,#include<iostream>结构化异常处理:C语言的函数执行过程中发现错误时,通常是通过返回一个特殊的值(如:-1、-2等)告诉调用者,调用者通过判断返回值来确定下一步的动作(正常处理或异常处理),这会使得两类代码交织在一起,难以理解与维护。C++通过try、throw、catch语句,把程序的正常处理与异常处理的代码分离开,使得程序容易理解与维护。......解决对小函数调用的低效问题函数调用是需要额外开销的,在执行函数体之前:保留返回地址为局部变量和形参分配空间实现参数传递......对一些只包含一两条语句的小函数,函数调用的额外开销往往大于完成函数功能所需要的开销,频繁地调用这样的函数将会使程序的效率不高。C++提供了两种解决上述问题的办法:带参数的宏定义(C已有的)内联函数(C++扩充的)带参数的宏定义宏定义是一种编译预处理命令,它可以实现类似函数的功能。例如,下面定义了一个带两个参数的宏:#define
max(a,b)
(((a)>(b))?(a):(b))在编译之前,编译预处理程序将对宏的使用进行文字替换!然后交给编译程序编译。例如:编译前将把程序中的cout<<max(x,y);替换成:cout<<(((x)>(y))?(x):(y));宏定义的格式为:#define凵<宏名>(<参数表>)凵<文字串>宏定义的不足之处需要加上很多的括号,否则会出问题。例如:#definemax(a,b)a>b?a:b10+max(x,y)+z将被替换成:10+x>y?x:y+z//?有时会出现重复计算。例如:#define
max(a,b)
(((a)>(b))?(a):(b))max(x+1,y*2)将被替换成:(((x+1)>(y*2))?(x+1):(y*2))//
x+1或y*2要计算2次替换时不进行参数类型检查和转换。
不利于一些工具(如调试)对程序的处理。例如,在上面程序的编译结果中,max已不存在!(10+x)>y?x:(y+z)内联函数内联函数是指在定义函数时,在函数返回类型之前加上一个关键词inline。例如:inlineintmax(inta,intb){ returna>b?a:b;}内联函数的作用是建议编译程序把该函数的函数体展开到调用点,不再进行函数调用,而是直接执行函数体。内联函数形式上属于函数,它遵循函数调用的一些规定。例如:编译程序会进行参数类型检查与转换。使用内联函数时应注意以下几点:不是所有函数都能作为内联函数,如递归函数往往不行。内联函数名具有文件作用域。带缺省值的形式参数对于一个函数的某些形参,会出现在调用这个函数时,大部分情况下给这些形参提供的实参都是某个固定值。例如,对下面的函数print,大部分情况下调用它时,参数base都是10:voidprint(intvalue,intbase);能否在调用时省略这些实参呢?例如 print(a);//a给value,10给base在C++中允许在声明函数时,为函数的某些参数指定默认值。例如,可以把函数print声明成: voidprint(intvalue,intbase=10);在调用这些函数时,如果没有提供相应的实参,则相应的形参采用指定的默认值。例如: print(32,2);//32传给value;2传给base print(28);//28传给value;10传给base在指定函数参数的默认值时,应注意下面几点:有默认值的形参应全处于形参表的右部。例如:voidf(inta,intb=1,intc=0);//OKvoidf(inta,intb=1,intc);//Error,c没指定默认值
对参数默认值的指定只在函数声明(包括定义性声明)处有意义。在不同的源文件中,对同一个函数的声明可以对它的参数指定不同的默认值。在同一个源文件中,对同一个函数的声明只能对它的每一个参数指定一次默认值。
名空间作用域对于一个由多个模块(源文件)构成的程序,有时会面临一个问题:在一个模块中要用到在另外两个模块中定义的不同全局程序实体(如:全局变量和函数),而这两个全局程序实体的名字相同。//模块1intx=1;voidf(){......}......//模块2intx=0;voidf(){......}......//模块3externintx;//?externvoidf();//?.........x,f...//?......C++提供了名空间(namespace)机制来解决上述的名冲突问题。可以把全局标识符定义在一个名空间中,其作用域为该名空间。当在一个名空间外部需要使用该名空间中定义的全局标识符时,需要用该名空间的名字来修饰或受限。//模块1namespaceA{ intx=1; voidf(){......}}//模块2namespaceB{ intx=0; voidf(){......}}...A::x...//A中的xA::f();//A中的f...B::x...//B中的xB::f();//B中的fusingnamespaceA;...x...//A中的xf();//A中的f...B::x...//B中的xB::f();//B中的fusingA::f;...A::x...//A中的xf();//A中的f...B::x...//B中的xB::f();//B中的f1.2.3.//模块3namespeceA//声明{externintx;voidf();}namespeceB//声明{externintx;voidf();}......由于C++标准库中的全局实体(如cin、cout)是定义在名空间std中的,因此,使用标准库中的全局实体时要用std受限。另外,具有文件作用域的标识符可以用无名的名空间来定义。例如,对于下面用static说明的具有文件作用域的全局变量: staticintx,y;可用下面的无名的名空间来代替: namespace {intx,y;//x和y只能在本源文件中使用! }这样,static就可以只用于一个目的了:使得局部变量采用静态存储分配。动态变量动态变量是指在程序运行中,由程序根据需要额外创建的变量。例如,下面创建一个int型动态变量,p1指向之:int*p1;//p1是个指针变量p1=(int*)malloc(sizeof(int));//#include<cstdlib>或p1=newint;//C++扩充再例如,下面创建一个由n个int型元素构成的动态数组,p2指向其第一个元素:int*p2;//p2是个指针变量p2=(int*)calloc(n,sizeof(int));//元素初始化为0或p2=(int*)malloc(sizeof(int)*n);或p2=newint[n];//C++扩充动态变量需要通过指针来访问动态变量没有名字!对动态变量的访问需要通过指向动态变量的指针变量来进行(间接访问)。例如:int*p,*q;p=newint;//p=(int*)malloc(sizeof(int));...*p...//访问p指向的int型动态变量q=newint[n];//q=(int*)calloc(n,sizeof(int));...*(q+i)
...//访问q指向的动态数组的第i个元素。
//也可以写成:...q[i]...程序实体在内存中的安排程序运行时,程序中的实体将存储在四个区域中:静态数据区:用于全局变量、static存储类的局部变量以及常量的内存分配。如果没有显式初始化,系统将把它们初始化成0。代码区:用于存放程序的指令,对C++程序而言,代码区存放的是所有函数代码。栈区:用于自动存储类的局部变量、函数的形式参数以及函数调用时有关信息(如:函数返回地址等)的内存分配。堆区:用于动态变量的内存分配。
静态数据区代码区栈区堆区在C++中,动态变量的生存期从用new或malloc(calloc)创建开始,直到程序用delete或free撤消它(使之消亡)结束。例如:int*p=newint;...*p...//动态变量生存期内,可访问deletep;//撤消p指向的int型动态变量或int*p=(int*)malloc(sizeof(int));...*p...//动态变量生存期内,可访问free(p);//撤消p指向的int型动态变量动态变量的生存期再例如:int*q=newint[n];...q[i]...//生存期内delete
[]q;//撤消q指向的动态数组或int*q=(int*)calloc(n,sizeof(int));...q[i]...//生存期内free(q);一般来说,用new创建的动态变量需要用delete来撤销;用malloc(calloc)创建的动态变量则需要用free撤销。动态变量的生存期可以跨函数。例如:int*f(){......
int*p=new
int;//动态变量生存期开始
...*p...//动态变量生存期内......//这里没有delete操作
returnp;}intmain(){int*q;
q=f();
...*q...//动态变量生存期内
deleteq;//动态变量生存期结束}用delete和free只能撤消动态变量!intx,*p;p=&x;deletep;//Error
用delete和free撤消动态数组时,其中的指针变量必须指向数组的第一个元素!int*p=newint[n];p++;//p指向数组第二个元素delete[]p;//Error,运行时出错!“内存泄漏”问题内存泄漏(memoryleak):没有撤消动态变量,而是把指向它的指针变量指向了别处或指向它的指针变量的生存期结束了,这时,这个动态变量虽然存在,但无法访问它,从而浪费空间。例如:intx,*p;p=newint[10];//动态数组p=&x;//之后,上面的动态数组就访问不到了!
//造成内存空间的丢失(内存泄露)再例如voidf(){int*p;
p=newint;//创建一个动态变量
......//其中没有delete}main{......
f();
......//f中创建的动态变量仍然存在,但由于指向它的
//指针变量p生存期已结束,无法通过p访问到它}“悬浮指针”问题悬浮指针(danglingpointer):用delete或free撤消动态变量后,指向它的指针就无效了(C++编译程序一般不会把指向它的指针变量的值赋为0),这时该指针可能指向一个无效空间。例如:int*p;p=newint;*p=1;deletep;//撤销了p所指向的动态变量......cout<<*p;//?int*q=newint;//创建一个新的动态变量*q=2;可能访问的是新的动态变量!动态变量的应用1――可扩充的数组对于具有线性结构的复合数据,在程序中通常用数组来表示。由于数组在定义时,元素个数必须是固定大小。当元素个数到运行时才能确定,下面的做法可行吗?intn;cin>>n;//数的个数inta[n];//?for(inti=0;i<n;i++)cin>>a[i];C语言的新标准允许在程序运行时指定数组元素个数,但是一旦指定后不能再改变!(上面数组a的大小不会随n变化)不是每个C++编译器都支持!解决方案1:如果输入时先输入数的个数,然后再输入各个数,则可用下面的动态数组来表示这些数:intn;int*p;cin>>n;p=newint[n];for(inti=0;i<n;i++)cin>>p[i];......//使用数组中的数据delete[]p;上面的动态数组大小也不会随n变化!解决方案2:如果输入时先输入各个数,最后输入一个结束标记(如:-1),如何表示这些数?先创建一个初始大小的动态数组,空间不够了再创建更大的动态数组constintINCREMENT=10;intmax_len=20,*p=newint[max_len];//申请初始的数组空间intx,n=0;for(cin>>x;x!=-1;cin>>x){ if(n==max_len) { max_len+=INCREMENT; int*q=newint[max_len];//重新申请一块更大的数组空间 for(inti=0;i<n;i++)q[i]=p[i];//转移数据 delete[]p;//归还原来的数组空间 p=q;//p指向新的数组空间 } p[n]=x; n++;}......//使用数组中的数据delete[]p;也可以利用库函数来实现数组的扩充p=(int*)malloc(max_len*sizeof(int));......max_len+=INCREMENT;p=(int*)realloc(p,max_len*sizeof(int));上面的实现方法虽然可行,但是,当数组空间不够时,它需要重新申请空间、进行数据转移以及释放原有的空间,这样做比较麻烦并且效率有时不高。当需要在数组中增加或删除元素时,它还将会面临数组元素的大量移动问题。a为一个一维数组(假设已有元素个数为n)删除数组a中位置m处的元素,赋给变量x。在数组a中位置m处插入一个元素x。循环怎么安排?数组元素的插入/删除操作//循环从前往后x=a[m];for(i=m+1;i<=n-1;i++)a[i-1]=a[i];n--;//循环从后往前for(i=n-1;i>=m;i--)a[i+1]=a[i];a[m]=x;n++;mn-1删除:前移0n-1m插入:后移0动态变量的应用2――链表链表用于表示由数量不定的同类型元素所构成的具有线性结构的复合数据。与动态数组不同:链表的每个元素都是一个动态变量,并且是逐个生成的,因此扩充容易。链表中的每一个元素除了本身的数据外,还包含一个(或多个)指针,它(们)指向链表中下一个(和其它)元素的内存位置,因此,各元素在内存中不必存放在连续的空间内。需要有一个指针(头指针)指向链表的第一个元素,要访问链表中的某个元素,一般要从第一个元素开始遍历(通过头指针)。在链表中插入/删除一个元素时一般只影响它前后两个元素。单链表的每个元素(又称结点或节点)只包含一个指向下一个元素的指针。结点类型可定义如下:structNode//结点的类型定义{ intcontent;//存储结点的数据
Node*next;//存储下一个结点的地址};另外需要一个头指针指向第一个结点,定义如下:Node*head=NULL;//头指针变量定义,初始状态下
//为空值。NULL在cstdio中定义为0
(头指针)heada1a2anNULL(链表元素)单链表链表与数组的结合数组与链表在表示线性元素构成的数据时各有特点:数组访问元素效率高,但空间扩充困难,插入/删除效率低。链表空间扩充容易,插入/删除效率高,但元素访问效率低。可以把它们结合起来使用:整体是链表,链表的每个结点中用数组存储多个元素。例如,结点的类型可以是:structNode//结点的类型定义{ intcontent[20];//最多存储20个元素的数据
intnum;//本结点中元素的实际个数
Node*next;//存储下一个结点的地址};访问元素时先找到元素所在的结点,在结点内部可用下标访问。增加/删除元素在某结点内部进行:结点内部空间不够时,可增加一个结点存放新元素。结点内部元素较少时,可合并相邻结点。引用类型引用类型是用来给一个变量取一个别名,通过该别名可以访问原来的变量:一个引用类型的变量没有自己的内存空间,而是共享它引用的变量的内存空间。例如:intx=10;int&y=x;//y为引用类型的变量,它是x的别名y=20;//通过y访问x,效果上等价于:x=20;引用类型具有指针类型的一些效果。例如:int*p=&x;//p为指针类型的变量,它指向x*p=30;//通过p访问x,效果上等价于:x=30引用主要用于函数的参数类型,实现指针类型参数的效果,但比指针类型抽象和安全。引用类型可提高参数传递的效率。例如:structA{inti;......};voidf(A&x)//x使用实参a的内存空间,提高参数传递效率{......…x.i…//访问实参
......}intmain(){Aa;......f(a);//把a传给函数f
......}引用类型可实现通过形参改变实参的值。例如:#include<iostream>usingnamespacestd;voidswap(int&x,int&y)//交换两个int型变量的值{ intt; t=x; x=y; y=t;}intmain(){ inta=0,b=1; cout<<a<<','<<b<<endl;//结果为:0,1 swap(a,b); cout<<a<<','<<b<<endl;//结果为:1,0 return0;}引用类型能保证通过形参访问的永远是实参数据。voidf(int*p){...*p...//通过p访问实参intm;p=&m;//OK
...*p...//访问m,即通过p可以访问实参以外的数据}voidg(int&x){...x...//通过x访问实参intm;x=&m;//Error…x…//通过x只能访问实参}intmain(){inta;f(&a);g(a);}当然,使用指针类型的常量也可以实现引用类型形参的这个效果:voidf(int*constp){...*p...//通过p访问实参intm;p=&m;//Error
...*p...//通过p只能访问实参}如何防止函数通过指针和引用类型的形参修改传进来的数据?voidf(int*p){cout<<*p;
*p=20;}voidg(int&x){cout<<x;
x=30;}......inta=10;f(&a);//调用中输出:10;cout<<a;//调用后a的值变成:20g(a);//调用中输出:20;cout<<a;//调用后a的值变成:30如何防止函数通过指针和引用类型的形参修改传进来的数据?voidf(constint*p){cout<<*p;
*p=20;//Error}voidg(constint&x){cout<<x;
x=30;//Error}......inta=10;f(&a);//调用中输出:10;cout<<a;//调用后a的值不变g(a);//调用中输出:10;cout<<a;//调用后a的值不变如何防止函数通过指针和引用类型的形参修改传进来的数据?voidf(constintx[],intnum){......
x[i]=20;//Error
......}......inta[10];......f(a,10);//调用后a的值不变函数返回值可以为引用类型structA{ intm; doublen;};A&func1(Ax[],intlen){......
//查找x中成员m为最大的元素,设其下标为i_maxreturnx[i_max];}Afunc2(Ax[],intlen){......
//查找x中成员m为最大的元素,设其下标为i_maxreturnx[i_max];}......Aa[10];......func1(a,10).n++;//a中成员m最大的元素的n的值增加了1func2(a,10).n++;//a中成员m最大的元素的n的值没变
!注意:不要把局部量的引用返回给调用者,因为函数返回后,局部量的内存空间已无效,后续操作中可能又分配给其它变量!例如:int&f(){inti=0;returni;}int&g(){intj=1;returnj;}intmain(){intx; x=f()+g();cout<<x<<endl;//输出:1?
return0;}可能是2引用类型的实现引用类型一般作为指针类型来实现(有时又把引用类型称作隐蔽的指针,hiddenpointer)对于下面的引用类型:voidf(int&m)//m是引用类型{cout<<m<<','//输出m的值(实参的值)
<<&m;//输出m的地址(实参的地址)}......intx=0,y=0;f(x);//f中的输出是x的值和地址f(y);//f中的输出是y的值和地址int&z=x;//z是引用类型z=1;cout<<x<<','<<z;//1,1cout<<&x<<&z;//结果一样!引用类型的实现引用类型一般作为指针类型来实现(有时又把引用类型称作隐蔽的指针,hiddenpointer)编译程序将按下面的指针类型来实现:voidf(int*m)//m是指针类型{cout<<*m<<','//输出m指向的值(实参的值)
<<m;//输出m的值(实参的地址)}......intx=0,y=0;f(&x);//f中的输出是x的值和地址f(&y);//f中的输出是y的值和地址int*z=&x;//z是指针类型*z=1;cout<<x<<','<<*z;//1,1cout<<&x<<z;//结果一样!函数名重载对于一些功能相同、参数类型或个数不同的函数,给它们取相同的名字有时会带来使用上的方便(便于理解和记忆)。例如,把下面不同的函数:voidprint_int(inti){......}voidprint_double(doubled){......}voidprint_char(charc){......}voidprint_A(Aa){......}//A为自定义类型定义为同名的函数:voidprint(inti){......}voidprint(doubled){......}voidprint(charc){......}voidprint(Aa){......}C++规定:在相同的作用域中,可以用同一个名字定义多个不同的函数,这时,要求定义的这些函数应具有不同的参数(参数个数或类型要有所不同)。上述的做法称为函数名重载。对重载函数调用的绑定确定一个对重载函数的调用对应着哪一个重载函数定义的过程称为绑定(binding,又称定联、联编、捆绑)。例如,print(1.0)调用的是下面的哪一个重载函数?voidprint(inti){......}voidprint(doubled){......}voidprint(charc){......}voidprint(Aa){......}对重载函数调用的绑定一般是在编译时刻由编译程序根据实参与形参的匹配情况来决定。重载函数的绑定规则从形参个数与实参个数相同的重载函数中,按下面的次序选择一个:精确匹配提升匹配标准转换匹配自定义转换匹配匹配失败精确匹配实参与形参的类型完全相同,或者对实参进行“微小”的类型转换后与形参类型相同:数组变量名->数组第一个元素的内存地址函数名->函数的内存首地址......例如,对于下面的重载函数定义:
voidprint(int); voidprint(double); voidprint(char);voidprint(char*);下面的函数调用:
print(1);//绑定到函数:voidprint(int); print(1.0);//绑定到函数:voidprint(double); print('a');//绑定到函数:voidprint(char);chars[10];
print(s);//绑定到函数:voidprint(char*);提升匹配先对实参进行下面的类型提升,然后进行精确匹配:按整型提升规则提升实参类型把float类型实参提升到double把double类型实参提升到longdouble例如,对于下述的重载函数:voidprint(int);voidprint(double);根据提升匹配,下面的函数调用:print('a');绑定到函数:voidprint(int);print(1.0f);绑定到函数:voidprint(double);
标准转换匹配先进行下面的标准转换,然后进行精确匹配:任何算术类型可以互相转换枚举类型可以转换成任何算术类型零可以转换成任何算术类型或指针类型任何类型的指针可以转换成void*例如,对于下述的重载函数:voidprint(char);voidprint(char*);根据标准转换匹配,下面的函数调用:print(1);绑定到函数:voidprint(char);每个标准转换都是平等的,不存在哪个优先:如果存在多个标准转换后能精确匹配,则失败!(具有歧义)
绑定失败如果不存在匹配或存在多个匹配,则绑定失败。例如,对于下述的重载函数:voidprint(char);voidprint(double);根据标准转换匹配,下面的函数调用将会绑定失败:print(1);因为1(属于int型)既可以转成char,又可以转成double解决办法是:对实参进行显式类型转换,如,print((char)1)或print((double)1)增加额外的重载,如,增加一个重载函数定义:voidprint(int);函数指针C++中可以定义一个指针变量(函数指针),使其指向一个函数,可以通过这个指针变量来调用它指向的函数。例如:doublef(intx){......}//f是一个函数......typedefdouble(*FP)(int);FPfp;//fp是一个指向函数的指针变量或者double(*fp)(int);//fp是一个指向函数的指针变量fp=&f;//fp指向函数f,
//也可写成:fp=f;(编译器会做类型转换!)(*fp)(10);//调用fp指向的函数f,
//也可写成:fp(10);(编译器会做类型转换!)向函数传递函数函数指针主要用于通过参数把一个函数传给另一个函数。例如:intfunc(int(*fp)(intx))//形参fp为一个函数指针类型的变量{inti; ...... ...(*fp)(i)...//或fp(i);调用fp所指向的函数(传进来的函数)
......}intf(intx){......}intg(intx){......}intmain(){ .........func(&f)...//或func(f);函数func中将调用f
...func(&g)...//或func(g);函数func中将调用g
.......}再例如,下面的函数integrate计算任意一个一元可积函数在一个区间上的定积分:doubleintegrate(double(*f)(double), doublea,doubleb){ doublex;
......
...f(x)...//调用f指向的函数}下面的函数调用分别用于计算一元函数my_func、sin和cos(它们都是参数为double,返回值为double的函数)在区间[1,10]、[0,1]和[1,2]上的定积分:integrate(my_func,1,10);integrate(sin,0,1);integrate(cos,1,2);回调函数(CallbackFunctions)一个函数在执行的过程中,有时需要该函数的调用者配合做些事,这可以通过由调用者提供一个函数来实现:原函数在执行的过程中需要调用者帮忙时,则可调用这个函数来完成。调用者提供的这个函数称为回调函数。回调函数通常是作为参数(函数指针)传给被调用者。例如:voidmain(...){......g(...,h);//调用者......}voidh(...)//回调函数{......}voidg(...,void(*fp)(...))//被调用者{......fp(...);//请求调用者协助......}回调函数的应用:编写一个能根据不同要求进行排序的函数structStudent{intno;
charname[20];
......};voidsort(Studentst[],intnum){......
if(st[i].no>st[j].no)//比较数组元素大小(i<j)
{......//交换st[i]与st[j]的位置
}
......}上述排序函数只能按no排序,并且是由小到大。如果还要按no由大到小排序呢?如果还要按name排序呢?一般要再写若干个排序函数,这些函数的实现代码基本相同,带来重复性编程工作,并容易造成不一致!如何只写一个函数就能按各种要求进行排序?可以给排序函数增加一个函数指针类型的参数,由调用者提供一个比较函数来指出两个元素的次序(该函数返回true为需要的序):voidsort(Studentst[],intnum,bool(*comp)(Student*st1,Student*st2)){......if(!comp(&st[i],&st[j])//根据comp返回值来决定数组元素位置{......//交换st[i]与st[j]的位置}......}boolless_than_by_no(Student*st1,Student*st2){return(st1->no<=st2->no);}boolgreater_than_by_no(Student*st1,Student*st2){return(st1->no>st2->no);}boolless_than_by_name(Student*st1,Student*st2){return(strcmp(st1->name,st2->name)<=0);}boolgreater_than_by_name(Student*st1,Student*st2){return(strcmp(st1->name,st2->name)>0);}......Studentst[100];......sort(st,100,less_than_by_no);//按学号由小到大排序sort(st,100,greater_than_by_no);//按学号由大到小排序sort(st,100,less_than_by_name);//按姓名由小到大排序sort(st,100,greater_than_by_name);//按姓名由大到小排序......匿名函数--λ表达式对于一些临时用一下的简单函数,如果也要先给出这个函数的定义并为之取个名字,然后再通过这个函数的名字来使用它们,在有些场合下会给程序编写带来不便。C++新国际标准(C++11)为C++提供了一种匿名函数机制――λ表达式(lambdaexpression),利用它可以实现把函数的定义和使用合而为一。例如,求函数x2在区间[0,1]的定积分:integrate([](doublex)->double{returnx*x;},0,1);上面黄颜色部分就是一个λ表达式不需要预先定义一个函数squareλ表达式的定义格式λ表达式的常用格式为:[<环境变量使用说明>]<形式参数><返回值类型指定><函数体><形式参数>:指出函数的参数及类型,其格式为:(<形式参数表>)如果函数没有参数,则这项可以省略。<返回值类型指定>:指出函数的返回值类型,其格式为:-><返回值类型>它可以省略,这时根据函数体中return返回的值隐式确定返回值类型。<函数体>为一个复合语句。<环境变量使用说明>:指出函数体中对外层作用域中的自动变量的使用限制:空:不能使用外层作用域中的自动变量。&:按引用方式使用外层作用域中的自动变量(可以改变这些变量的值)。=:按值方式使用使用外层作用域中的自动变量(不能改变这些变量的值)。&和=可以用来统一指定对外层作用域中自动变量的使用方式,也可以用来单独指定可使用的外层自动变量(变量名前可以加&,默认为=)。下面是一些合法的λ表达式:{intk,m,n;//环境变量.........[](intx)->int{returnx*x;}...//不能使用k、m、n...[&](intx)->int{k++;m++;n++;
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年中职(新能源汽车检测与维修)电池管理系统单元测试题及答案
- 2025年高职建筑工程(门窗工程施工)试题及答案
- 2025年中职安全(应用实操技巧)试题及答案
- 2025年大学第三学年(艺术教育)舞蹈教学方法试题及答案
- 2025年中职大数据与会计(财务审计基础)试题及答案
- 2025年中职(环境监测技术)环境工程基础试题及答案
- 2025年大学护理学(护理质量管理)试题及答案
- 2025年高职物流装卸搬运管理(装卸搬运管理)试题及答案
- 2025年大学卫生检验与检疫(卫生检疫研究)试题及答案
- 2026年德州职业技术学院单招综合素质考试备考题库带答案解析
- 浙江省2025年初中学业水平考试浙真组合·钱塘甬真卷(含答案)
- (高清版)DB34∕T 5225-2025 风景名胜区拟建项目对景观及生态影响评价技术规范
- 社区矫正面试试题及答案
- 《察今》(课件)-【中职专用】高二语文(高教版2023拓展模块下册)
- GB/T 30425-2025高压直流输电换流阀水冷却设备
- GB/T 45355-2025无压埋地排污、排水用聚乙烯(PE)管道系统
- 2025年园长大赛测试题及答案
- 地图用户界面设计-深度研究
- 生命体征的评估及护理
- 2024年国家公务员考试行测真题附解析答案
- 电梯采购与安装授权委托书
评论
0/150
提交评论