函数返回值 constconst引用和普通引用的区别

温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
&int &func(){static int num = 0; / /静态变量&&&&&&& return ++}&&&void main(){&&&&&&&&&&&&&&& for(i=0; i&5; i++)&&&&&&&&&&& cout&&func()&&'\t';&&&&&&& cout&&&&&& func()=10;&&&&&&&& for(i=0; i&5; i++)&&&&&&&&&&& cout&&func()&&'\t';&&&&&&& cout&&}返回值: 1 & &2 & 3 & 4 & 5
11 12 13 14 15 下面再给出一个使用返回引用的函数作为左值的例子,它更有力地揭示了返回引用的函数的本质。&#include &iostream&&double array[5] = {100.1, 100.2, 100.3, 100.4, 100.5};&double &change(int i){&&&&&&& return array[i];}&int main(){&&&&&&&&&&& cout&&"原始值如下: ";&&&&&&& for(i = 0; i & 5; i++)&&&&&&&&&&& cout && array[i] &&" ";&&&&&&& cout&&&&&&&&&& change(2) = 3.14; & //将3.14复制change(2)返回引用的隐式执政&&&&&&& change(3) = -99.99;&&&&&&&& cout&&"修改后如下: ";&&&&&&& for(i = 0; i & 5; i++)&&&&&&&&&&& cout&&array[i]&&" ";&&& cout&&&&&& return 0;}&编译并运行上述程序,其输出结果请读者自己实验吧。函数change的返回值为double类型的引用,而该值又是一个由其参数i指定的数组array中元素的引用。因此,在主函数中,当语句“change(2) = 3.14;”被执行时,change函数返回的其实是对数组元素array[2]的引用。通过这个引用,array[2]被赋值3.14。随后的语句“change(3) = -99.99;”同此原理。由于change返回的是数组中特定元素的引用,所以该函数可以放在赋值语句的左边用来对这个数组元素进行赋值。注意前面讲过没有数组的引用,但是指向数组元素的引用时存在的。 注意点:当函数返回引用类型时,没有复制返回值,相反,返回的是对象本身千万不要返回局部对象的引用!千万不要返回指向局部对象的指针!不能返回临时变量的引用,也就是说被引用的对象不能超出作用域。 当函数执行完毕时,将释放分配给局部对象或临时变量的存储空间。此时对局部对象的引用就会指向不确定的内存!返回指向局 部对象的 也是一样的,当函数结束时,局部对象被释放,返回的指针就变成了不再存在的对象的悬垂指针。返回引用时,要求返回全局变量/对象或者静态变量或const常量的引用,若是返回值在函数的参数中,包含有以引用方式或指针方式存在的。不能返回函数内部动态分配的内存的引用。虽然不存在局部变量的被动销毁的问题,但是在此种情况下,仍然存在一些问题。例如,被函数返回的引用只是作为一个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的由new分配的空间就无法被释放,从而造成内存泄漏问题。//正确方式int& abc(int a, int b, int c, int& result){
result = a + b +
return}//错误方式int& abc(int a, int b, int c){ return a + b +//临时变量}4、返回const类型由于返回值直接指向了一个生命期尚未结束的变量,因此,对于函数返回值(或者称为函数结果)本身的任何操作,都在实际上,是对那个变量的操作,这就是引入const类型的返回的意义。当使用了const关键字后,即意味着函数的返回值不能立即得到修改!如下代码,将无法编译通过,这就是因为返回值立即进行了++操作(相当于对变量z进行了++操作),而这对于该函数而言,是不允许的。如果去掉const,再行编译,则可以获得通过,并且打印形成z = 7的结果。&include &iostream&include &cstdlib&const int& abc(int a, int b, int c, int& result){
result = a + b +
return}int main(){
int a = 1; int b = 2; int c=3;
abc(a, b, c, z)++;
//wrong: returning a const reference
cout && "z= " && z &&
return 0;}5、例子下面是一个段有错误的代码,找出其中的错误。//错误代码#include &iostream&using namespaceint val() {
int i = 1;
return } int & ref() {
int main() {
vv = val();
int & rv = val();
vr = ref();
int & rr = ref();
return 0;} //修改后的正确代码#include &iostream&using namespaceint j=3;//j是全局变量int val() {
int i = 1;
return } int & ref() { //
int j=3;j不能是局部变量!
return //不能返回局部对象的引用}
int main() {
vv = val();
rv = val();//int
&rv = val()错误!val()返回的是一个int型的数,而给引用&rv 赋值的必须是一个同类型的变量。
vr = ref();
int & rr = ref();
cout&&vv&&
cout&&rv&&
cout&&vr&&
cout&&rr&&
return 0;} 最后讨论下函数非引用返回和引用返回对返回值的复制次数:对于函数的返回值,看似简单,但并非如此,比如:int func(int a);该函数会返回一个int型,如果进行一个调用int result=func(3);会发生什么情况?首先,func将返回值复制到一个匿名临时变量中,在这里假设该临时变量为anony(其实是没有名字的,这里方便阐述);然后,再将anony的值复制到result,可以看出,这里是进行了两次复制的。而并非一次复制。&对于返回引用的函数:int & func(int &a);假设该函数传入一个int的引用,然后再func中修改它,再返回其引用,如果调用int reslut=func(b);会发生如下情况:返回的是b的引用,因此相当于直接将b的值复制给了result。这里就只有一次复制(少了临时变量的复制,当然也创建了一个临时变量,只是该临时变量是b的一个引用)。需要特别注意的是,按很多人的理解,这里返回的是一个引用,因此result就是b的引用,其实并非如此,这里返回引用只是减少了一次临时变量值的复制。如果真的要让result能够引用b,可以这样做:int &result = func(b);注:返回普通变量的引用看不出效率的差异,但是返回比较大的类或者结构体的时候效率差异比较明显。&那如果是这样申明函数int func(int a);注意,这里返回的不是引用。然后int &result=func(a);会发生什么情况呢?如果是这样,编译器将报错:不能用一个临时变量来初始化一个非常量的引用变量。要消除这种报错,可以这样写const int &result=func(a);这样虽然返回的不是引用,但是由于最后赋给的是一个引用变量,因此在返回过程中也只有一次复制过程。但是这样的result是不能修改其引用的内容的。&还有一种看似更为诡异但却十分合理的情况:int &func (int &a);同样假设该函数传入一个int的引用,在func中修改它,然后返回其引用。然后这样调用func(b)=3;这样的后果是,传入的b的值变为3。原因是func返回了一个b的引用,然后再将该引用赋为3,因此b的值也变成了3。如果要禁止这种情况的发送,可以这样声明函数:const int &func(int &a);这样返回的是一个const引用,它不允许使用该引用修改其指向的值。因此如果有func(b)=3这样的调用,将通不过编译。数据结构学习笔记(一):参考文章:
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
loftPermalink:'',
id:'fks_',
blogTitle:'数据结构学习笔记(5)——函数返回值(引用返回、非引用返回)',
blogAbstract:'\t函数的返回主要分为以下几种情况:1、主函数main的返回值:\t允许主函数main没有返回值就可结束;可将主函数main返回的值视为状态指示器,返回0表示程序运行成功,其他大部分返回\t值则表示失败。2、返回非引用类型:',
blogTag:'',
blogUrl:'blog/static/3',
isPublished:1,
istop:false,
modifyTime:9,
publishTime:1,
permalink:'blog/static/3',
commentCount:0,
mainCommentCount:0,
recommendCount:0,
bsrk:-100,
publisherId:0,
recomBlogHome:false,
currentRecomBlog:false,
attachmentsFileIds:[],
groupInfo:{},
friendstatus:'none',
followstatus:'unFollow',
pubSucc:'',
visitorProvince:'',
visitorCity:'',
visitorNewUser:false,
postAddInfo:{},
mset:'000',
remindgoodnightblog:false,
isBlackVisitor:false,
isShowYodaoAd:false,
hostIntro:'',
hmcon:'0',
selfRecomBlogCount:'0',
lofter_single:''
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}2011年9月 C/C++大版内专家分月排行榜第二2011年4月 C/C++大版内专家分月排行榜第二2010年11月 C/C++大版内专家分月排行榜第二
2011年6月 C/C++大版内专家分月排行榜第三
2011年9月 C/C++大版内专家分月排行榜第二2011年4月 C/C++大版内专家分月排行榜第二2010年11月 C/C++大版内专家分月排行榜第二
2011年6月 C/C++大版内专家分月排行榜第三
本帖子已过去太久远了,不再提供回复功能。豆丁微信公众号
君,已阅读到文档的结尾了呢~~
c++函数返回引用
扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
C++函数返回引用和const的应用
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='http://www.docin.com/DocinViewer-.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口[第二节]C++ 引用
函数调用作为左值 用const限定引用 返回堆中变量的引用
函数调用作为左值
  在上节中,对于第三种情况,也意味着返回一个引用使得一个函数调用表达式成为左值表达式。只要避免将局部栈中变量的地址返回,就能使函数调用表达式作为左值来使用运行得很好。
  例如,下面的程序是统计学生中A类学生与B类学生各占多少。 A类学生的标准是平均分在80分以上,其余都是B类学生,先看不返回引用的情况
    //*********************
    //**   ch9_7.cpp  **
    //*********************
    #include &iostream.h&
    int array[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 getLevel(int grade[], int size);
    void main()
     int typeA=0,typeB=0;
     int student=6;
     int gradesize=4;
     for(int i=0; i& i++) //处理所有的学生
      if(getLevel(array[i], gradesize))
       typeA++;
      else
       typeB++;
     cout &&&number of type A is & &&typeA &&
     cout &&&number of type B is & &&typeB &&
    int getLevel(int grade[], int size)
     int sum=0;
     for(int i=0; i& i++) //成绩总分
      sum+=grade[i];
     sum/= //平均分
     if(sum&=80)
       return 1; //type A student
     else
       return 0; //type B student
  运行结果为:
    number of type A iS 3
    number of type B iS 3
  该程序通过函数调用判明该学生成绩属于A类还是B类, 然后给A类学生人数增量或给B类学生人数增量。
  该程序也可以通过返回引用来实现。返回的引用作为左值直接增量。例如:
    //*********************
    //**   ch9_8.cpp  **
    //*********************
    #include &iostream.h&
    int array[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(int grade[], int size, int& tA, int& tB);
    void main()
     int typeA=0,typeB=0;
     int student=6;
     int gradesize=4;
     for(int i=0; i& i++) //处理所有的学生
      level(array[i],gradesize,typeA,typeB)++;
        //函数调用作为左值
     cout &&&number of type A is & &&typeA &&
     cout &&&number of type B is & &&typeB &&
    int& level(int grade[], int size,int& tA, int& tB)
     int sum=0;
     for(int i=0; i& i++) //成绩总分
      sum+=grade[i];
     sum/= //平均分
     if(sum&=80)
      return tA; //type A student
     else
      return tB; //type B student
  该程序中的level()函数返回一个引用, 为了返回一个非局部变量的引用,就要传递两个引用参数typeA和typeB。当该学生属于A类时,就返回typeA的引用,否则就返回typeB的引用。
由于返回的是引用,所以可以作为左值直接进行增量操作。该函数调用代表typeA还是typeB的左值视具体的学生成绩统计结果而定。
  本例说明:返回引用的函数,可以使函数成为左值。在后面章节中,我们将会看到,这一应用是很多的,最典型的是cout和cin的操作符重载。
  -&上面各个图中,对引用的表示依赖于实现。引用变量概念上是不占空间的,引用变量被理解为粘附在初始化的实体上,它的实现对用户来说不可见。但并不等于具体实现的时候,非得不占任何空间。为了帮助理解引用,让你有个引用实现的感性认识,表示了一种实现的方案,图中引用空间用来存放所代表变量的地址。
用const限定引用
  传递指针和引用更大的目的是效率。 当一个数据类型很大(后面章节中介绍的自定义类型)时,因为传值要复制副本,所以不可取。
  另一方面,传递指针和引用存在传值所没有的危险。程序有时侯不允许传递的指针所指向的值被修改或者传递的引用被修改,但传递的地址特征使得所传的参数处于随时被修改的危险之中。
  保护实参不被修改的办法是传递const指针和引用:
  例如,下面的程序传递一个const double型的常量指针,返回一个指针:
    //*********************
    //**   ch9_9.cpp  **
    //*********************
    #include &iostream.h&
    double* fn(const double* pd)
     static double ad=32;
     ad+=*
     cout&&&fn being called..the value is:&&&*pd&&
     return &
    void main()
     double a=345.6;
     const double* pa=fn(&a);
     cout &&*pa &&
     a=55.5;
     pa = fn(&a);
     cout &&*pa &&
  运行结果为:
    fn being called...the value is:345.6
    377.6
    fn being called...the value iS:55.5
    433.1
  程序中fn()函数声明的参数为double型的常量指针,返回double型的指针。函数fn()中,没有生成实参a的副本,访问*pd就是直接访问a。尽管a是变量,但由于限定了pd的性质,所以在fn()函数的作用域范围内,pd只能以*pd的形式读出a,而不能修改a。
  函数fn()中,定义了一个静态局部变量ad。在返回时,将其地址返回给了主函数中的常量double的指针pa, 使之通过*pa能读出ad的值而不能修改之。但在函数fn()中,ad是变量。是可以被修改的。
  将上面的程序改成传递引用与返回引用,函数处理起来会更容易,可读性也更好:
    //**********************
    //**   ch9_10.cpp  **
    //**********************
    #include &iostream.h&
    double& fn(const double& pd)
     static double ad=32;
     ad+=
      cout&&&fn being called..the value is:&&&pd&&
     
    void main()
     double a=345.6;
     double& pa=fn(a);
     cout &&pa &&
     a=55.5;
     pa = fn(a);
     cout &&pa &&
  运行结果为:
    fn being called...the value is:345.6
    377.6
    fn being called...the value iS:55.5
    433.1
  程序ch9_10.cpp与ch9_9.cpp的输出是一样的。 唯一明显的区别是现在的函数fn()以const double的引用为参数,返回double的引用。用引用比用指针更简单些,而且程序达到相同的效率, 也具有使用const所提供的安全性。
  -&C++不区分变量的const引用和const变量的引用。 程序决不能给引用本身重新赋值,使它指向另一个变量, 因此引用总是const的。如果对引用应用关键词const,其作用就是 使目标成为const变量。即没有:
    const double const &a=1;
  只有:
    const double &a=1;
返回堆中变量的引用
  对引用的初始化,可以是变量,可以是常量,也可以是一定类型的堆空间变量。但是,由于引用不是指针,所以,下面的代码直接从堆中获得的变量空间来初始化引用是错的:
    int& a=new int(2); //a不是指针
  考虑操作符new。 如果new不能在堆空间成功地获得内存分配, 它返回NULL。因为引用不能是NULL,在程序确认它不是NULL之前,程序不能用这一内存初始化引用。
  例如,下面的代码说明如何处理这一校验:
    #include&iostream.h&
    void fn()
     int * pInt=new int;
     if(pInt==NULL)
     {
      cout&&&error memory allocation!&;
      return;
     }
     int& rInt*pInt;
     //...
  int的指针pInt获得new返回的值,程序测试pInt中的地址,如果它是NULL,则报告错误信息并返回。 如果它不是NULL,则将*pInt初始化引用rInt。如此,rInt成为new返回的别名。
  用堆空间来初始化引用,要求该引用在适当时候释放堆空间。
  例如,下面的程序在堆中分配空间,求值,然后释放堆空间:
    //**********************
    //**   ch9_11.cpp  **
    //**********************
    #include &iostream.h&
    int CircleArea()
     double* pd=
     if(!pd){
      cout &&&error memory allocation!&;
      
     }
     double& rd=*
     cout &&&the radius is: &;
     cin &&
     cout&&&the area of circle is &&&rd*rd*3.14 &&
     delete &
     
    void main()
     if(CircleArea())
      cout &&&program failed.\n&;
     else
      cout &&&program successed.\n&;
  运行结果为:
    the radius is:12
    the area of circle is 452.16
    program successed.
  在计算圆面积的CircleArea()中, double指针接受new返回的堆空间地址,然后进行有效性校验。如果有效, 则将*pd初始化引用rd,rd接受键盘输入,计算,打印输出圆面积,返还堆空间,并正常返回。否则输出错误信息,返回出错标志。
  这里,返还堆空间有两种方式,一个是deletepd,另一个是delete &rd,因为&rd和pd都指向同一个堆空间地址。对引用来说,同===样存在由一个函数建立的堆内存由另一个函数释放的问题,我们在第8章有过类似的说明。
  对使用堆的引用,有下面的经验:
  ·必要时用值传递参数
  ·必要时返回值
  ·不要返回有可能退出作用域的引用
  ·不要引用空目标
  -&引用和指针使函数的“黑盒”性被打破。函数可以访问不属于自己栈空间的内存。这对把握不住C++的人来说是危险的, 而对熟练的程序员来说,正是引用和指针才使函数只能返回单一值的状态被打破,使得函数功能更趋强大。函数的副作用是良性还是恶性, 各A自有评说,对于函数潜在的破坏性,是放任自流,还是要适当地抑制, 专家们动尽了脑筋,直到C++类机制的实现,才使函数的恶性作用得以控制。
  引用是C++独有的特性。 指针存在有种种问题,间接引用指针会使代码可读性差, 易编程出错。而引用正好扬弃了指针。 引用的使用中,单纯取个别名是毫无意义的,引用的目的主要用于在函数参数传递中,解决大对象的传递效率和空间都不如意的问题。本章主要介绍引用的原理和各种语法现象,未涉及到大对象,它在以后各章陆续介绍。引用能够保证参数传递中不产生副本,从而发挥指针的威力,提高传递的效率, 通过const的使用,保证了引用传递的安全性。
  引用是C++语言学习中的一个难点。有的人C的背景知识不是很强,他们经常一开始不管在什么地方都使用引用,除非有的地方必须使用指针。而另一些学习C++的C程厅员则通常避免使用引用,只是把它们作为另一种传递地址的方法来考虑。由于指针也能做这项工作.所以他们只使用指针。这都是片面的。
  引用具有表达清晰的优点。引用将对传递参数的责任赋给了编写函数的程序员,而不是使用它们的各个用户。引用是对操作符重载必不可少的补充(见14.7节)。引用通过传递地址提高了函数运行的效率。引用传递与值传递在使用方法上比较,唯一区别在函数的形式参数声明。
  不允许声明引用数组,可以用常量来初始化引用声明。返回引用时,要注意局部对象返回的危险。要注意引用隐藏函数所使用的参数传递的类型。
看过本文的人也看了:
我要留言技术领域:
取消收藏确定要取消收藏吗?
删除图谱提示你保存在该图谱下的知识内容也会被删除,建议你先将内容移到其他图谱中。你确定要删除知识图谱及其内容吗?
删除节点提示无法删除该知识节点,因该节点下仍保存有相关知识内容!
删除节点提示你确定要删除该知识节点吗?const函数和const引用区别是什么_百度知道
const函数和const引用区别是什么
int func(const int&); const int &func(int); int func(int) const int &func(const int&)const都是什么意思
我有更好的答案
final Matcher mat = pattern.matcher(email);;
final Pattern pattern = Patternboolean tag = true?//.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+);
final String pattern1 = &^([a-z0-9A-Z]+[-|//.)+[a-zA-Z]{2!mat.compile(pattern1);
if (,}$&quot
为您推荐:
其他类似问题
const的相关知识
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。}

我要回帖

更多关于 返回const引用 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信