什么是引用?

引用是C++语言的一个特殊的数据类型描述,用于在程序的不同的部分使用两个以上的变量名指向同一块地址,使得对其中任何一个变量的操作实际上都是对同一地址单元进行的。

使用时的注意事项:

引用的特点:

1.一个变量可取多个别名。

2.引用必须初始化。

3.引用只能在初始化的时候引用一次 ,不能更改为转而引用其他变量。

4.对引用进行操作,实际上就是对被引用的变量进行操作,

5.引用仅是变量的别名,而不是实实在在地定义了一个变量,因此引用本身并不占用内存,而是和目标变量共同指向目标变量的内存地址.声明引用时,目标的存储状态不会改变

6.表达式中的取地址符&不再是取变量的地址,而是用来表示该变量是引用类型的变量。

引用的应用:

1.基础引用:

void TestReference1 ()
{
int a = 1;
int& b = a;
  b=2;
cout<<"a:address->" <<&a<< endl;
cout<<"b:address->" <<&b<< endl;
//输出结果a,b都等于2 }

2.const引用:

 常引用声明方式:const  类型标识符  &引用名 = 目标变量名;

  用这种方式声明的引用,不能通过引用对目标变量的值进行修改,从而使引用的目标成为const,达到了引用的安全性。

#include<iostream.h>
void main(){
int a=1;
int &b=a;
b=2;
cout<<"a="<<a<<endl;//2
int c=1;
const int &d=c;
// d=2;//编译错误 error C2166: l-value specifies const object
c=2;//正确
}

  这不光是让代码更健壮,也有其它方面的需求。

 【例4】:假设有如下函数声明:

    string foo();

    void bar(string &s);

  那么下面的表达式将是非法的:

    bar(foo());

    bar("hello world");

  原因在于foo( )和"hello world"串都会产生一个临时对象,而在C++中,临时对象都是const类型的。因此上面的表达式就是试图将一个const类型的对象转换为非const类型,这是非法的。

  引用型参数应该在能被定义为const的情况下,尽量定义为const 。

3.引用作参数:

1.【值传递】
void Swap (int left, int right) {
int temp = left;
left = right ;
right = temp ;
} 2.【引用传递】
void Swap (int& left, int& right)//使用引用的话,不做临时拷贝,&的使用说明此处只是原参数的另一个名字而已,所以修改时直接在原参数的基础上修改变量值。
{
int temp = left;
right = left ;
left = temp ;
} 3.【指针传递】
void Swap (int* pLeft, int* pRight)//传入的是地址,因为地址是唯一的,所以指针通过地址的访问进而可修改其内容。
{
int temp = *pLeft;
*pLeft = *pRight;
*pRight = temp;
}

//函数参数的传递方式:值传递,地址传递,引用(c++),如何选择呢?

//看是否要修改值,要修改,用指针或者引用,不必修改,则用值传递

//对于指针和引用,看传进来的是不是地址或者时new 出来的,是则选指针,不是则选择引用


由上例可以看出:

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

  (2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本;如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。

  (3)使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用\"*指针变量名\"的形式进行运算,这很容易产生错误且程序的阅读性较差;

另一方面,在主调函数的调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰。

  如果既要利用引用提高程序的效率,又要保护传递给函数的数据不在函数中被改变,就应使用常引用。

4. 引用作为返回值

说明:

  (1)以引用返回函数值,定义函数时需要在函数名前加&

  (2)用引用返回一个函数值的最大好处是,在内存中不产生被返回值的副本。

 以下程序中定义了一个普通的函数fn1(它用返回值的方法返回函数值),另外一个函数fn2,它以引用的方法返回函数值。

#include <iostream>
using namespace std;
float temp;//定义全局变量temp
float fn1(float r);//声明函数fn1
float &fn2(float r);//声明函数fn2 r
float fn1(float r){//定义函数fn1,它以返回值的方法返回函数值
temp=(float)(r*r*3.14);
return temp;
} float &fn2(float r){//定义函数fn2,它以引用方式返回函数值
temp=(float)(r*r*3.14);
return temp;
} int main(){
float e=10.0;
float a=fn1(10.0);//第1种情况,系统生成要返回值的副本(即临时变量)
// float &b=fn1(10.0); //第2种情况,可能会出错(不同 C++系统有不同规定)
/*error: invalid initialization of non-const reference of type 'float&' from an rvalue of type 'float'
*/
//不能从被调函数中返回一个临时变量或局部变量的引用
float c=fn2(10.0);//第3种情况,系统不生成返回值的副本
//可以从被调函数中返回一个全局变量的引用
float &d=fn2(10.0); //第4种情况,系统不生成返回值的副本
e=d; cout<<"a="<<a<<",c="<<c<<",d="<<d<<",e="<<e<<endl;
//a=314,c=314,d=314
return 0;
} 

引用作为返回值,必须遵守以下规则:

  (1)不能返回局部变量的引用。主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成为了"无所指"的引用,程序会进入未知状态。

  (2)不能返回函数内部new分配的内存的引用。例如,被函数返回的引用只是作为一个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成memory leak。

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

  (4)引用与一些操作符的重载:流操作符<<和>>,这两个操作符常常希望被连续使用,例如:cout << \"hello\" << endl; 因此这两个操作符的返回值应该是一个仍然支持这两个操作符的流引用。

 引用虽方便,使用须谨慎:

(1)&在这里不是求地址运算,而是起标识作用。

(2)类型标识符是指目标变量的类型。

(3)声明引用时,必须同时对其进行初始化。

(4)引用声明完毕后,相当于目标变量名有两个名称,即该目标原名称和引用名,且不能再把该引用名作为其他变量名的别名。

(6)不能建立引用的数组。因为数组是一个由若干个元素所组成的集合,所以无法建立一个由引用组成的集合,但是可以建立数组的引用。

(7)引用常见的使用用途:作为函数的参数、函数的返回值。

* 引用和指针的区别和联系(笔试热点)

★不同点:

1.指针的作用有:(1).装地址(2).不同变量访问同一块空间

 引用:只可以实现用不同变量访问同一块空间

2.引用定义了就一定要初始化,指针不用

3.引用初始化后就不能再引用其他空间了

4. 没有空的引用,指针可以为空(引用一定要保证引用的时一个合法的存储单元)(在c++中NULL就是0,而c中的NULL是空地址(void*)0)

5. “sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身(所指向的变量或对象的地址)的大小;

6. 指针和引用的自增(++)运算意义不一样;引用是值的增减,指针是地址的偏移

7.从内存分配上看:程序为指针变量分配内存区域,而引用不需要分配内存区域。

★相同点:两者都是地址的概念,指针指向一块儿内存,其内容为所指内存的地址;引用是某块儿内存的别名。

指针比引用更为灵活,但是其风险也很大。使用指针时一定要检查指针是否为空(NULL),且空间回收后指针最好置零,以免野指针的发生造成内存泄漏等问题。

参考资料:

http://www.cnblogs.com/gw811/archive/2012/10/20/2732687.html(引用与多态)

http://blog.csdn.net/xiao__tian__/article/details/51814617

https://www.cnblogs.com/jycboy/p/5184638.html

http://blog.csdn.net/mysunshinetbg/article/details/48346195

c++中的引用详解的更多相关文章

  1. php中关于引用(&)详解

    php中关于引用(&)详解 php的引用(就是在变量或者函数.对象等前面加上&符号) 在PHP 中引用的意思是:不同的变量名访问同一个变量内容. 与C语言中的指针是有差别的.C语言中的 ...

  2. JavaScript正则表达式详解(二)JavaScript中正则表达式函数详解

    二.JavaScript中正则表达式函数详解(exec, test, match, replace, search, split) 1.使用正则表达式的方法去匹配查找字符串 1.1. exec方法详解 ...

  3. AngularJS select中ngOptions用法详解

    AngularJS select中ngOptions用法详解   一.用法 ngOption针对不同类型的数据源有不同的用法,主要体现在数组和对象上. 数组: label for value in a ...

  4. 【转载】C/C++中extern关键字详解

    1 基本解释:extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义.此外extern也可用来进行链接指定. 也就是说extern ...

  5. Objective-C中的@Property详解

    Objective-C中的@Property详解 @Property (属性) class vairs 这个属性有nonatomic, strong, weak, retain, copy等等 我把它 ...

  6. WCF中队列服务详解

    WCF中队列服务详解 一.引言 在前面的WCF服务中,它都要求服务与客户端两端都必须启动并且运行,从而实现彼此间的交互.然而,还有相当多的情况希望一个面向服务的应用中拥有离线交互的能力.WCF通过服务 ...

  7. C++引用(&)详解

    C++引用详解 引用的概念 引用:就是某一变量(目标)的一个别名,对引用的操作与对变量直接操作完全一样. 引用的声明方法:类型标识符 &引用名=目标变量名: 如下:定义引用ra,它是变量a的引 ...

  8. C++11 左值、右值、右值引用详解

    C++11 左值.右值.右值引用详解 左值.右值 在C++11中所有的值必属于左值.右值两者之一,右值又可以细分为纯右值.将亡值. 在C++11中可以取地址的.有名字的就是左值,反之,不能取地址的.没 ...

  9. PHP之PHP文件引用详解

    HP的文件引用涉及到四个函数: 文件引用 1.include()2.include_once()3.require()4.require_once() 这四个函数常常会给PHP初学者造成困扰,总的来说 ...

随机推荐

  1. QAQ的LIS树 QAQ的LIS树2 题解报告

    这两道题实际上考试的时候是一道题OwO 太可怕了,忙了我三个多小时,写了整整7K 这个题两个询问关联性不强,所以分开来考虑 QAQ的LIS树 考虑如何用dp求解答案 设dp(v)表示v到根的修改后的序 ...

  2. python中hasattr, getattr,setattr及delattr四个方法

    通过一个实例来说明,这四个函数的用法: 首先一个如下的一个简单的类: class Animal(object): def __init__(self,name, zone): self.name = ...

  3. mongodb 最佳可视化工具mongobooster

    最好用的mongodb GUI工具 mongobooster,没有之一,可从https://mongobooster.com/下载 常见管理命令可参考,http://www.cnblogs.com/l ...

  4. nginx/ajax跨子域请求的两种现代方法以及403解决

    因为面向互联网的性质,我们公司的大部分系统都采用多子域的方式进行开发和部署,以达到松耦合和分布式的目的,因此子系统间的交互不可避免.虽然通过后台的rpc框架解决了大部分的交互问题,但有些情况下,前端直 ...

  5. VS编译器之间相互打开的技巧

    例如:VS2010的工程在VS2012上打开,在工程属性里面 选择“常规” --> "平台工具集中"   选择 正在打开版本的型号.

  6. 【资源】分享一个最新版sublime 3143的注册码,亲测可用

    注:请勿用作商业用途,有能力者请购买正版!!! —– BEGIN LICENSE —– TwitterInc 200 User License EA7E-890007 1D77F72E 390CDD9 ...

  7. loj 诗歌

    链接 链接 思路 好久之前的考试题了吧,之前貌似抄的题解 现在理解了怕忘了,就写个题解记录一下吧,题目还是不错的 枚举中间点j \[H_{i}-H_{j}=H_{j}-H_{k}\] \[H_{k}+ ...

  8. SQL 收集

    1.union CREATE TABLE dbo.#testTab ( Id int NOT NULL ) insert into #testTab values(); insert into #te ...

  9. POJ 2348 Euclid's Game(博弈)题解

    题意:有a,b两个数字,两人轮流操作,每次可以选择两个之中较小的数字,然后另一个数字减去选择数字的任意倍数(不能减到负数),直到其中一个为0,不能操作为败 思路:这题用博弈NP思想,必败点和必胜点之间 ...

  10. redis持久化RDB和AOF-转载

    Redis 持久化: 提供了多种不同级别的持久化方式:一种是RDB,另一种是AOF. RDB 持久化可以在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot). AO ...