作者: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()函数的返回值类型是引用类型,不过因为这个函数返回的不是局部变量,所以没有警告,顺利编译通过。