(根据《C++程序设计》(谭浩强)整理,整理者:华科小涛,@http://www.cnblogs.com/hust-ghtao转载请注明)
对一个数据可以建立一个“引用”,它的作用是为一个变量起一个别名。这是C++对C的一个重要扩充。本系列分两篇,本篇为基础篇,主要是介绍基本知识。
1 基本概念及注意事项
1.1 引用概念
假如有一个变量a,想给它起一个别名b,可以这样写:
1: int a ;
2: int &b = a ; //声明b是a的“引用”
以上声明了b是a的引用,即b是a的别名。经过这样的声明后,使用a和b的作用相同,都代表同一个变量。注意:在上述声明中,&是引用声明符,并不代表地址。在数据类型名出现的&是引用声明符,在其他场合出现的都是取地址符。声明变量b为引用,并不需要另外开辟内存单元来存放b的值。b和a占内存中同一内存单元它们具有同一地址。即声明b是a的引用,可以理解为:使变量b具有变量a的地址。
1.2 注意事项
(1)引用不是一种独立的数据类型。对引用只有声明,没有定义。
必须先定义一个变量,然后声明对该对象建立一个引用。关于定义和引用的具体区别,将会在近期的博客中整理。暂时可以简单的这样理解:变量定义,用于为变量分配存储空间,还可为变量指定初始值;变量声明,用于向程序表明变量的类型和名字。
(2)声明一个引用时,必须同时使之初始化,即声明它代表哪一个变量。
注意:当引用作为函数形参时不必在声明中初始化,它的初始化是在函数调用时的虚实结合实现的,即作为形参的引用是实参的别名。
(3)声明一个引用后,不能再使之作为另一个变量的引用。
比如声明了b是变量a的引用后,在其有效作用范围内,b始终与其代表的变量a联系,不能在作为其他变量的引用,例如下面的用法就不合法:
1: int a1 ,a2 ;
2: int &b = a1 ; //声明b是a1的引用
3: int &b = a2 ; //试图使b又变成a2的引用,不合法
(4)不能建立引用数组。
下面的用法不合法:
1: int a[5] ;
2: int &b[5] = a ; //错误,不能建立引用数组
3: int &b = a[0] ; //错误,不能建立数组元素的引用
(5)不能建立引用的引用。
下面的用法也不合法:
1: int a = 3 ;
2: int &b = a ; //声明b是a的引用,正确
3: int &c = b ; //错误,试图建立引用的引用
2 引用的应用
唉?好奇怪啊,有了变量名,为什么还需要一个别名呢?C++之所以增加引用机制,主要一个方面就是把它作为函数的参数,以扩充函数传递数据的功能。闲话少说,上例子!
为了说明引用的作用,我们写函数实现两个数据值得交换。有人说这还不简单,信手拈来嘛:
1: void swap (int a ,int b)
2: {
3: int temp = a ;
4: a = b ;
5: b = temp ;
6: }
若在主函数中调用此函数,试图交换变量i和j的值:
1: int i = 3 ;
2: int j = 5 ;
3: swap(i,j) ;
唉,好奇怪,怎么没有得到正确答案呢?这就要说道函数参数传递的机制了,这位同 学想通过改变形参的值,而改变实参的值,但是他用的函数参数传递机制却是:
(1) 将变量名作为实参和形参。
这时传给形参的是变量的值,传递是单向的.如果在执行函数期间形参的值发生变化,并不传回给实参.因为在函数调用时,形参和实参不是同一个存储单元。
那又有同学说了,那可以传递变量的地址啊,说着就写出了下述程序:
1: void swap(int* p1 ,int* p2)
2: {
3: int temp ;
4: temp = *p1 ;
5: *p1 = *p2 ;
6: *p2 = temp ;
7: }
也在主函数中测试了一下:
1: int i = 3 ;
2: int j = 5 ;
3: swap(&i,&j) ;
然后测试i,j的值,得到了正确答案。这位同学是利用了第二种参数传递的机制:
(2)传递变量的地址。
形参是指针变量,实参是一个变量的地址,调用函数时,形参(即指针变量)得到实参变量的地址,从而指向实参变量单元。调用函数时把变量i和j的地址传送给形参p1和p2 。所以p1就指向变量i,p2就指向j。通过交换指针所指的值,当然就交换了i和j 。这种方式通过形参变量指针访问主函数中的变量,并改变它们的值,虽然能得到正确结果,但是在概念上却是兜了一个圈子。下面就介绍第三种写法:
1: void swap(int &a , int &b)
2: {
3: int temp ;
4: temp = a ;
5: a = b ;
6: b = temp ;
7: }
主函数中:
1: int i = 3 ;
2: int j = 5 ;
3: swap(i,j) ;
也得到了正确结果。这里用到了第三种参数传递机制:
(3)以引用作为形参,在虚实结合中建立变量的引用,使形参名作为实参的引用,即形参称为实参的引用。
当main函数调用swap函数时,进行虚实结合,把实参变量i和j的地址传递给形参a和b,使a称为i的别名,b称为j的别名,当然a和b的值交换了,i和j的值也交换了。这就是地址传递方式。
那么这三种传递参数的方式有啥不同呢:
其实上述三种传递方式,可归纳为两种:传值方式和传址方式。
传值方式:(1)和(2)是传值方式,在(1)中,把变量i和j的值传递给形参a和b。在(2)中,把&i和&j的值传递给指针变量p1和p2 。在此方式中实参是地址(&i和&j),传递的是地址,故仍然是传值方式,不是传址方式。传值方式在调用函数时,需要对形参分配存储单元。
传址方式:(3)为此方式,实参不是地址而是变量名,由于形参是引用,系统会自动的将形参的地址传递给形参。注意:此时传送的是地址而不是实参变量的值。
总结一下:用引用形参的方法比使用指针简单、直观、方便,可以部分代替指针的操作。当然这只是引用的用处之一,引用的厉害指出多着呢,待后续娓娓道来。。。