作者:jicanmeng
时间:2014年11月26日
引用(reference)是C++引入的一种新的数据类型,在C语言中是没有的。learncpp.com上面是这样描述的:References are a type of C++ variable that act as an alias to another variable.
声明一个引用类型的变量,这个变量会和一个已经分配的内存空间绑定在一起。假设内存空间使用变量var1来表示,那么s声明一个引用变量var2就相当于为var1起了一个"绰号",var1和var2表示是相同的一块内存空间。由于内存空间已经分配,所以编译时不会为引用本身分配内存空间。
在声明一个引用类型的变量时,必须为其指定绑定的内存空间,即声明引用的时候必须进行初始化。声明引用的时候使用符号"&"。看一个例子:
程序如下:
#include <iostream> using namespace std; int main(){ int a = 3; int &b = a; int &c(a); b = 4; cout << "a is " << a << endl; c = 5; cout << "a is " << a << endl; return 0; }
程序运行结果如下:
[jicanmeng@andy tmp]$ g++ reference1.cpp
[jicanmeng@andy tmp]$ ./a.out
a is 4
a is 5
[jicanmeng@andy tmp]$
声明一个引用类型的变量有两种形式,分别如第6行和第7行所示。声明了引用变量b和c后,a变量,b变量,c变量表示相同的内存空间。修改b就相当于修改a和c,修改c就相当于修改a和b。
在c语言中学习指针的时候,定义一个指针变量时:int a = 3; int *pointer = &a;
,*表示定义的变量是指针类型的。而在正常使用时:*pointer = 4;
, *是指针运算符,*pointer表示取指针变量pointer指向的内存的数据。
类似的,定义一个引用变量时:int a = 3; int &b = a;
,&表示定义的变量是引用类型的。而在正常使用时:int *pointer = &b
,&则表示取地址运算符,&b表示得到b表示的内存的地址。
指针和引用的区别如下:1. 指针本身要占用内存空间,而引用不需要;2. 引用是一个已分配内存空间的另一个标识,一旦初始化,他们的关系就确定下来,不可再修改。而指针指向另一个内存空间,指向可以更改。
c++中已经有了指针,为什么还要在添加一个引用类型呢?learncpp.com上给的解释是:Because references always “point” to valid objects, and can never be pointed to deallocated memory, references are safer to use than pointers.
reference有两个典型的应用场景:1. 函数的参数为引用类型;2. 函数的返回值类型为引用类型。
第一种场景:函数的参数类型为引用类型:
#include <iostream> using namespace std; void foo(int &y) // y is now a reference { cout << "y = " << y << endl; y = 6; cout << "y = " << y << endl; } // y is destroyed here int main() { int x = 5; cout << "x = " << x << endl; foo(x); cout << "x = " << x << endl; return 0; }
第二种场景:函数的返回值类型为引用类型。这里需要详细的说明一下如果返回的是一个局部变量的情况。函数的返回值可以通过传值返回,也可以通过传递引用返回,也可以通过传递指针返回。
1. 函数的返回值通过传值返回:
#include <iostream> using namespace std; int DoubleValue(int nX) { int nValue = nX * 2; return nValue; // A copy of nValue will be returned here } // nValue goes out of scope here int main() { int a = 3; cout << "return value is " << DoubleValue(a) << endl; return 0; }
在这种方式下,当返回局部变量时,其实程序会将nValue复制一份返回给调用者。
2. 函数的返回值通过传递引用或传递指针返回:
#include <iostream> using namespace std; int & DoubleValue(int nX) { int nValue = nX * 2; return nValue; // return a reference to nValue here } // nValue goes out of scope here int main() { int a = 3; cout << "return value is " << DoubleValue(a) << endl; return 0; }
#include <iostream> using namespace std; int * DoubleValue(int nX) { int nValue = nX * 2; return &nValue; // return nValue by address here } // nValue goes out of scope here int main() { int a = 3; int *pa = DoubleValue(a); cout << "return value is " << *pa << endl; return 0; }
上面的两个程序都会提示警告:"warning: reference to local variable ‘nValue’ returned" 或者"warning: address of local variable ‘nValue’ returned"。因为函数调用结束后,局部变量会释放分配的内存空间,我们却返回了这块内存空间的引用和指针,所以会出现警告。其实,只要我们返回的是某块不释放的内存的引用或指针,都不会有警告的。
上面提到,声明一个引用变量其实是对一块已经存在的内存空间进行绑定,这块内存空间常常使用变量名表示。来看一种特殊情况:一个指针变量表示的内存空间。我们看一个例子:
#include <iostream> using namespace std; int & multiply2(int *&nX) { *nX = *nX * 2; return *nX; } int main() { using namespace std; int a = 3; int *pa = &a; int b = multiply2(pa); cout << "a is " << a << "b is " << b << endl; return 0; }
这个例子中,注意两个地方:1. multiply2()函数的参数nX是指针类型的引用变量,表示nX绑定的内存空间用于存放int类型的变量的地址,nX和pa表示的是相同的内存空间。2. multiply2()函数的返回值类型是引用类型,不过因为这个函数返回的不是局部变量,所以没有警告,顺利编译通过。