什么是引用,使用引用应该注意的问题

news/2024/7/3 23:20:54 标签: 存储, class, string, leak, c, 语言
cle class="tags" href="/tags/CLASS.html" title=class>class="baidu_pl">
cle_content" class="tags" href="/tags/CLASS.html" title=class>class="article_content clearfix">
content_views" class="tags" href="/tags/CLASS.html" title=class>class="htmledit_views">

答:引用就是某个目标变量的“别名”(alias)࿰c;对应用的操作与对变量直接操作效果完全相同。申明一个引用的时候࿰c;切记要对其进行初始化。引用声明完毕后࿰c;相当于目标变量名有两个名称࿰c;即该目标原名称和引用名࿰c;不能再把该引用名作为其他变量名的别名。声明一个引用࿰c;不是新定义了一个变量࿰c;它只表示该引用名是目标变量名的一个别名࿰c;它本身不是一种数据类型࿰c;因此引用本身不占class="tags" href="/tags/CLASS.html" title=class>class="tags" href="/tags/CunChu.html" title=存储>存储单元࿰c;系统也不给引用分配class="tags" href="/tags/CLASS.html" title=class>class="tags" href="/tags/CunChu.html" title=存储>存储单元。不能建立数组的引用。

3. 将“引用”作为函数参数有哪些特点?

(1)传递引用给函数与传递指针的效果是一样的。这时࿰c;被调函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用࿰c;所以在被调函数中对形参变量的操作就是对其相应的目标对象(在主调函数中)的操作。

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">(2)使用引用传递函数的参数࿰c;在内存中并没有产生实参的副本࿰c;它是直接对实参操作;而使用一般变量传递函数的参数࿰c;当发生函数调用时࿰c;需要给形参分配class="tags" href="/tags/CLASS.html" title=class>class="tags" href="/tags/CunChu.html" title=存储>存储单元࿰c;形参变量是实参变量的副本;如果传递的是对象࿰c;还将调用拷贝构造函数。因此࿰c;当参数传递的数据较大时࿰c;用引用比用一般变量传递参数的效率和所占空间都好。

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">(3)使用指针作为函数的参数虽然也能达到与使用引用的效果࿰c;但是࿰c;在被调函数中同样要给形参分配class="tags" href="/tags/CLASS.html" title=class>class="tags" href="/tags/CunChu.html" title=存储>存储单元c;且需要重复使用"*指针变量名"的形式进行运算࿰c;这很容易产生错误且程序的阅读性较差;另一方面࿰c;在主调函数的调用点处࿰c;必须用变量的地址作为实参。而引用更容易使用࿰c;更清晰。

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">4. 在什么时候需要使用“常引用”? 

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">如果既要利用引用提高程序的效率࿰c;又要保护传递给函数的数据不在函数中被改变࿰c;就应使用常引用。常引用声明方式:const 类型标识符 &引用名=目标变量名;

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">例1

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">int a ;
const int &ra=a;
ra=1; //错误
a=1; //正确

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">例2

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">class="tags" href="/tags/STRING.html" title=string>string foo( );
void bar(class="tags" href="/tags/STRING.html" title=string>string & s);

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">那么下面的表达式将是非法的:

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">bar(foo( ));
bar("hello world");

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">原因在于foo( )和"hello world"串都会产生一个临时对象࿰c;而在C++中࿰c;这些临时对象都是const类型的。因此上面的表达式就是试图将一个const类型的对象转换为非const类型࿰c;这是非法的。

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">引用型参数应该在能被定义为const的情况下࿰c;尽量定义为const 。

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">5. 将“引用”作为函数返回值类型的格式、好处和需要遵守的规则?

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">格式:类型标识符 &函数名(形参列表及类型说明){ //函数体 }

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">好处:在内存中不产生被返回值的副本;(注意:正是因为这点原因࿰c;所以返回一个局部变量的引用是不可取的。因为随着该局部变量生存期的结束࿰c;相应的引用也会失效࿰c;产生runtime error!

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">注意事项:

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">(1)不能返回局部变量的引用。这条可以参照Effective C++[1]的Item 31。主要原因是局部变量会在函数返回后被销毁࿰c;因此被返回的引用就成为了"无所指"的引用࿰c;程序会进入未知状态。

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">(2)不能返回函数内部new分配的内存的引用。这条可以参照Effective C++[1]的Item 31。虽然不存在局部变量的被动销毁问题࿰c;可对于这种情况(返回函数内部new分配内存的引用)࿰c;又面临其它尴尬局面。例如࿰c;被函数返回的引用只是作为一个临时变量出现࿰c;而没有被赋予一个实际的变量࿰c;那么这个引用所指向的空间(由new分配)就无法释放࿰c;造成memory class="tags" href="/tags/LEAK.html" title=leak>leak

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">(3)可以返回类成员的引用࿰c;但最好是const。这条原则可以参照Effective C++[1]的Item 30。主要原因是当对象的属性是与某种业务规则(business rule)相关联的时候࿰c;其赋值常常与某些其它属性或者对象的状态有关࿰c;因此有必要将赋值操作封装在一个业务规则当中。如果其它对象可以获得该属性的非常量引用(或指针)࿰c;那么对该属性的单纯赋值就会破坏业务规则的完整性。

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">(4)流操作符重载返回值申明为“引用”的作用:

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">流操作符<<和>>࿰c;这两个操作符常常希望被连续使用࿰c;例如:cout << "hello" << endl; 因此这两个操作符的返回值应该是一个仍然支持这两个操作符的流引用。可选的其它方案包括:返回一个流对象和返回一个流对象指针。但是对于返回一个流对象࿰c;程序必须重新(拷贝)构造一个新的流对象c;也就是说࿰c;连续的两个<<操作符实际上是针对不同对象的!这无法让人接受。对于返回一个流指针则不能连续使用<<操作符。因此࿰c;返回一个流对象引用是惟一选择。这个唯一选择很关键࿰c;它说明了引用的重要性以及无可替代性࿰c;也许这就是C++语言中引入引用这个概念的原因吧。赋值操作符=。这个操作符象流操作符一样࿰c;是可以连续使用的࿰c;例如:x = j = 10;或者(x=10)=100;赋值操作符的返回值必须是一个左值࿰c;以便可以被继续赋值。因此引用成了这个操作符的惟一返回值选择。

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">例3

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">#i nclude <iostream.h>
int &put(int n);
int vals[10];
int error=-1;
void main()
{
put(0)=10; //以put(0)函数值作为左值࿰c;等价于vals[0]=10; 
put(9)=20; //以put(9)函数值作为左值࿰c;等价于vals[9]=20; 
cout<<vals[0]; 
cout<<vals[9];

int &put(int n)
{
if (n>=0 && n<=9 ) return vals[n]; 
else { cout<<"subscript error"; return error; }
}

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">(5)在另外的一些操作符中࿰c;却千万不能返回引用:+-*/ 四则运算符。它们不能返回引用c;Effective C++[1]的Item23详细的讨论了这个问题。主要原因是这四个操作符没有side effect࿰c;因此࿰c;它们必须构造一个对象作为返回值࿰c;可选的方案包括:返回一个对象、返回一个局部变量的引用࿰c;返回一个new分配的对象的引用、返回一个静态对象引用。根据前面提到的引用作为返回值的三个规则࿰c;第2、3两个方案都被否决了。静态对象的引用又因为((a+b) == (c+d))会永远为true而导致错误。所以可选的只剩下返回一个对象了。

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">6. “引用”与多态的关系?

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">引用是除指针外另一个可以产生多态效果的手段。这意味着࿰c;一个基类的引用可以指向它的派生类实例。

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">例4

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">Class A; Class B : Class A{...};   B b; A& ref = b;

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">7. “引用”与指针的区别是什么?

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">指针通过某个指针变量指向一个对象后࿰c;对它所指向的变量间接操作。程序中使用指针࿰c;程序的可读性差;而引用本身就是目标变量的别名࿰c;对引用的操作就是对目标变量的操作。此外࿰c;就是上面提到的对函数传ref和pointer的区别。

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">8. 什么时候需要“引用”?

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">流操作符<<和>>、赋值操作符=的返回值、拷贝构造函数的参数、赋值操作符=的参数、其它情况都推荐使用引用。

class="tags" href="/tags/CLASS.html" title=class>class="main" style="line-height:normal">以上 2-8 参考:color:#0000ff; line-height:normal">http://blog.csdn.net/wfwd/archive/2006/05/30/763551.aspx

cle>

http://www.niftyadmin.cn/n/1404367.html

相关文章

高速pcb布线注意要点

大家都知道理做PCB板就是把设计好的原理图变成一块实实在在的PCB电路板,请别小看这一过程,有很多原理上行得通的东西在工程中却难以实现,或是别人能实现的东西另一些人却实现不了,因此说做一块PCB板不难,但要做好一块PCB板却不是一件容易的事情。 微电子领域的两大难点在于高频…

2440从NANDFlash启动之bootloader运行以前 (转)

http://bluefish.blog.51cto.com/214870/67093原文地址 一直对2440上电以后怎么从nandflash中启动不是很清楚&#xff0c;闲来无事看了下s3c2440的用户手册&#xff0c;看到下面这样一段话&#xff1a; S3C2440A boot code can be executed on an external NAND flash mem…

抢红包 (25 分)

抢红包 (25 分) 没有人没抢过红包吧…… 这里给出N个人之间互相发红包、抢红包的记录&#xff0c;请你统计一下他们抢红包的收获。 输入格式&#xff1a; 输入第一行给出一个正整数N&#xff08;≤10 ​4 ​​ &#xff09;&#xff0c;即参与发红包和抢红包的总人数&#xf…

使用KITL的详细教程

在几个以前&#xff0c;我曾经玩过一下子KITL&#xff0c;但是那时候什么都不懂&#xff0c;根本没有了解KITL是什么东西&#xff0c;更别说是工作原理了&#xff0c;这段时间都是在调试一些键盘等本机驱动&#xff08;系统启动时候就启动的驱动&#xff09;&#xff0c;这个驱…

#pragma data_seg用法总结

#pragma data_seg用法总结2009-02-06 13:05Windows在一个Win32程序的地址空间周围筑了一道墙。通常&#xff0c;一个程序的地址空间中的数据是私有的&#xff0c;对别的程序而言是不可见的。但是执行STRPROG的多个执行实体表示了STRLIB在程序的所有执行实体之间共享数据是毫无问…

愿天下有情人都是失散多年的兄妹 (25 分)

愿天下有情人都是失散多年的兄妹 (25 分) 呵。大家都知道五服以内不得通婚&#xff0c;即两个人最近的共同祖先如果在五代以内&#xff08;即本人、父母、祖父母、曾祖父母、高祖父母&#xff09;则不可通婚。本题就请你帮助一对有情人判断一下&#xff0c;他们究竟是否可以成…

strcpy()、memcpy()、memmove()、memset()的实现

strcpy(), 字符串拷贝. char *strcpy(char *strDest, const char *strSrc) { assert((strDest!NULL) && (strSrc !NULL)); char *address strDest; while( (*strDest * strSrc) ! \0) NULL ; return address ; } memcpy, 拷贝不…