C++学习之路—引用(一)—基础知识

(根据《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)为此方式,实参不是地址而是变量名,由于形参是引用,系统会自动的将形参的地址传递给形参。注意:此时传送的是地址而不是实参变量的值。

    总结一下:用引用形参的方法比使用指针简单、直观、方便,可以部分代替指针的操作。当然这只是引用的用处之一,引用的厉害指出多着呢,待后续娓娓道来。。。

原文地址:https://www.cnblogs.com/hust-ghtao/p/3633384.html