11.2 C++中的引用
引用(reference)(&)就像能自动地被编译器间接引用的常量型指针。它通常用于函数的参数表中和函数的返回值,但也可以独立使用。例如:
在行(1)中,编译器分配了一个存储单元,它的值被初始化为12,于是这个引用就和这个存储单元联系上了。应用要点是任何引用必须和存储单元联系。访问引用时,就是在访问那个存储单元。因而,如果写行(2)和(3),那么增加a事实上就是增加x,这个可在main()函数中显示出来。思考一个引用的最简单的方法是把它当做一个奇特的指针。这个指针的一个优点是不必怀疑它是否被初始化了(编译器强迫它初始化),也不必知道怎样对它间接引用(这由编译器做)。
使用引用时有一定的规则:
1)当引用被创建时,它必须被初始化(指针则可以在任何时候被初始化)。
2)一旦一个引用被初始化为指向一个对象,它就不能改变为另一个对象的引用(指针则可以在任何时候指向另一个对象)。
3)不可能有NULL引用。必须确保引用是和一块合法的存储单元关联。
11.2.1 函数中的引用
最经常看见引用的地方是在函数参数和返回值中。当引用被用做函数参数时,在函数内任何对引用的更改将对函数外的参数产生改变。当然,可以通过传递一个指针来做相同的事情,但引用具有更清晰的语法。(如果愿意的话,可以把引用看做一个使语法更加便利的工具。)
如果从函数中返回一个引用,必须像从函数中返回一个指针一样对待。当函数返回时,无论引用关联的是什么都应该存在,否则,将不知道指向哪一个内存。
下面有一个例子:
对函数f()的调用缺乏使用引用的方便性和清晰性,但很清楚这是传递一个地址。在函数g()的调用中,地址通过引用被传递,但表面上看不出来。
11.2.1.1 常量引用
仅当在Reference.cpp中的参数是非常量对象时,这个引用参数才能工作。如果是常量对象,函数g()将不接受这个参数,这样做是一件好事,因为这个函数将改变外部参数。如果知道这函数不妨碍对象的不变性的话,让这个参数是一个常量引用将允许这个函数在任何情况下使用。这意味着,对于内建类型,这个函数不会改变参数,而对于用户定义的类型,该函数只能调用常量成员函数,而且不应当改变任何公共的数据成员。
在函数参数中使用常量引用特别重要。这是因为我们的函数也许会接受临时对象,这个临时对象是由另一个函数的返回值创立或由函数使用者显式地创立的。临时对象总是不变的,因此如果不使用常量引用,参数将不会被编译器接受。看下面一个非常简单的例子:
调用f(1)会产生编译期间错误,这是因为编译器必须首先建立一个引用,即编译器为一个int类型分派存储单元,同时将其初始化为1并为其产生一个地址和引用捆绑在一起。存储的内容必须是常量,因为改变它没有任何意义—我们再不能对它进行操作。对于所有的临时对象,必须同样假设它们是不可存取的。当改变这种数据的时候,编译器会指出错误,这是非常有用的提示,因为这个改变会导致信息丢失。
11.2.1.2 指针引用
在C语言中,如果想改变指针本身而不是它所指向的内容,函数声明可能像这样:
当传递它时,必须取得指针的地址:
对于C++中的引用,语法清晰多了。函数参数变成指针的引用,用不着取得指针的地址。因此,
通过运行这个程序,将会看到指针本身增加了,而不是它指向的内容增加了。