引用有两种类型:左值引用(lvalue reference) 和 右值引用 (rvalue reference) 。
左值引用是传统 C++ 的一种引用方式;右值引用是 C++11 新标准中的一个特性。
左值引用是另一个变量的别名,之所以称之为“左值引用”是因为它引用的是一个可出现在赋值操作符左边的持久存储位置。因为左值引用是别名而非指针,所以声明引用时必须指出对应的变量,也就是要一开始要明确初始化。与指针不同的是,不能修改引用使其表示另一个变量。
与左值引用一样, 右值引用也可以用作变量的别名,它与左值引用的区别在于它也能引用右值 --- 实质上,这是一个暂存的临时值。
声明与初始化左值引用
[Plain Text] 纯文本查看 复制代码 long number(0L);
long &rnumber(number); // 声明长整型变量 number 的引用
rnumber += 10L // 使变量 number 加 10
int &refData = 5; //这是错误的用法,不会被编译通过。字面量 5 是一个常数,并且不能被改变,为了保持常量值的完整性,必须使用一个 const 引用:
const int &refData = 5; // 正确用法
声明并初始化右值引用
在类型名后面使用两个 & 来指定一个 rvalue 引用类型,如:rx 引用了 x 。这表明可以用一个左值来初始化一个右值引用,从而使右值引用能够像左值引用一样工作。还可以写成:
[Plain Text] 纯文本查看 复制代码 int && rExpr = 2*3 + 3;
在这里,右值引用初始化为引用表达式 2*x + 3 的求值结果,它是一个临时值。注意,左值引用不能这么做。上面仅仅是一种示例,并没有什么实际用途,但在其它的一些情况中右值引用会有很大的用处。
右值引用形参
下面简单的说明右值引用类型的函数形参和左值引用类型的函数形参的差别。看下面的代码:
[Plain Text] 纯文本查看 复制代码 // Using an rvalue reference parameter
#include <iostream>
using std::cout;
using std::endl;
int incr10(int&& num); // Function prototype
int main(void)
{
int num(3);
int value(6);
int result(0);
/*
result = incr10(num); // Increment num
cout << endl << "incr10(num) = " << result
<< endl << "num = " << num;
result = incr10(value); // Increment value
cout << endl << "incr10(value) = " << result
<< endl << "value = " << value;
*/
result = incr10(value+num); // Increment an expression
cout << endl << "incr10(value+num) = " << result
<< endl << "value = " << value;
result = incr10(5); // Increment a literal
cout << endl << "incr10(5) = " << result
<< endl << "5 = " << 5;
cout << endl;
return 0;
}
// Function to increment a variable by 10
int incr10(int&& num) // Function with rvalue reference argument
{
cout << endl << "Value received = " << num;
num += 10;
return num; // Return the incremented value
}
输出结果:Value received = 9
incr10(value+num) = 19
value = 6
Value received = 5
incr10(5) = 15
5 = 5 函数 incr10() 有一个右值引用类型参数。在 main() 中,使用表达式 value + num 作为实参来调用 incr10() 函数。输出结果表明,函数的返回值是表达式的值加 10 。如果我们将一个左值引用形参来对应表达式实参的传递,编译器就会报错。
另外,字面量 5 作为实参时,函数执行了加 10 的操作,但从输出结果中可以看到,字面量 5 并没有改变,这是为什么呢?这里,实参是一个只由字面量 5 组成的表达式。表达式的求值结果为 5,并且存储在函数形参引用的临时位置。
虽然右值引用形参可以引用一个右值 --- 即表达式的临时结果,但右值引用形参本身并不是一个右值,而是一个左值。
从函数返回引用
从函数中可以返回一个左值引用。返回引用就像返回指针一样容易产生潜在的错误,因此需要小心。因为左值引用不能独自(它总是其他对象的别名)存在,所以必须确保其引用的对象在函数执行完之后仍然存在。不过这在函数中使用引用时很容易忘记这一点,因为它们看起来就像是普通的变量。
下面是一个函数返回引用的示例。该程序的主要作用是,找出数组中的最小值,并人为的替换。
[Plain Text] 纯文本查看 复制代码 // Returning a reference
#include <iostream>
#include <iomanip>
using std::cout;
using std::endl;
using std::setw;
double& lowest(double values[], int length); // Function prototype
int main(void)
{
double array[] = { 3.0, 10.0, 1.5, 15.0, 2.7, 23.0,
4.5, 12.0, 6.8, 13.5, 2.1, 14.0 };
int len(sizeof array/sizeof array[0]); // Initialize to number
// of elements
cout << endl;
for(int i = 0; i < len; i++)
cout << setw(6) << array[i];
lowest(array, len) = 6.9; // Change lowest to 6.9
lowest(array, len) = 7.9; // Change lowest to 7.9
cout << endl;
for(int i = 0; i < len; i++)
cout << setw(6) << array[i];
cout << endl;
return 0;
}
// Function returning a reference
double& lowest(double a[], int len)
{
int j(0); // Index of lowest element
for(int i = 1; i < len; i++)
if(a[j] > a[i]) // Test for a lower value...
j = i; // ...if so update j
return a[j]; // Return reference to lowest
// element
}
输出结果:
3 10 1.5 15 2.7 23 4.5 12 6.8 13.5 2.1 14
3 10 6.9 15 2.7 23 4.5 12 6.8 13.5 7.9 14
lowest() 函数返回的是数组元素 a[j] 的引用,而不是该元素包含的值。注意不要混淆返回 &a[j] 与 返回引用。如果将返回值写作 &a[j] ,那么指定的是 a[j] 的地址 --- 这是个指针。如果错误的写成 &a[j] ,你会看到编译器(VC++2010)提示的错误: error C2440: “return”: 无法从“double *”转换为“double &”
返回引用的规则
从函数返回指针的规则同样适用于返回引用:永远不要从函数中返回局部变量的引用。 |