必备技能6.5:返回引用
在C++中,函数可以返回一个引用。函数返回引用有好几种用法,其中一些我们会在本书的后面讲到。这里我们涉及其中的一部分。
如果一个函数返回的是一个引用,那么它实际上暗含地返回了一个指向返回值的指针。这就出现了一个令人乍舌的情况:函数可以出现在一个赋值语句的左侧!例如下面的程序:
//函数返回引用 #include <iostream> using namespace std; double &f(); //函数f()返回引用 double val = 100.0; int main() { double x ; cout << f() << '\n'; //输出val的值 x = f(); //把val的值赋值给x cout << x << '\n'; //输出x的值 f() = 99.1; //修改val的值 cout << f() << '\n'; //输出val的值 return 0; } double &f() { return val; //返回全局变量val的引用 }
100
100
99.1
我们仔细研究一下上面的程序。在程序的开始,函数f()被声明为返回一个double类型的引用,全局变量val被初始化为100。在main()函数中,采用了下面的语句打印val的初始值:
cout << f() << '\n'; //输出val的值
当调用函数f()的时候,它返回val的引用:
return val; //返回全局变量val的引用
该句自动地返回了对val的引用,而不是val的值。然后我们使用这个引用在cout语句中输出其值。
在下面的一行:
x = f();//把val的值赋值给x
通过函数f()返回的引用把val的值赋值给x。程序中最有意思的一行就是下面的代码:
f() = 99.1; //修改val的值
这句将使得变量val的值被修改为99.1。原因如下:既然函数f()返回的是对val的引用,那么该引用就是赋值的对象。这样一来,99.1就被间接地通过函数f()返回的引用赋值给了val。
下面是另外一个使用返回引用的示例程序:
//返回数组元素的引用 #include <iostream> using namespace std; double &change_it(int i); //函数返回引用 double vals[] = { 1.1, 2.2, 3.3, 4.4, 5.5 }; int main() { int i; cout << "Here are the original values: "; for ( i = 0; i < 5; i++) { cout << vals[i] << ' '; } cout << '\n'; change_it(1) = 5298.23; //修改第二个元素的值 change_it(3) = -98.8; //修改第四个元素的值 cout << "There are the changed values: "; for ( i = 0; i < 5; i++) { cout << vals[i] << ' '; } cout << '\n'; return 0; } double &change_it(int i) { return vals[i]; //返回对第i个元素的引用 }
程序通过使用返回引用的函数修改了数组的第二个和第四个元素的值。输出如下:
Here are the original values: 1.1 2.2 3.3 4.4 5.5
There are the changed values: 1.1 5298.23 3.3 -98.8 5.5
让我们来看看这一点是如何实现的。
函数change_it被声明为返回double类型引用。更为明确地说,它返回的是对数组vals的第i个元素的引用。在main()函数中,这个引用被用在赋值语句中来给元素赋值。
当返回引用的时候,必须注意返回的对象不能超越它的作用范围。例如下面的程序:
//错误!不能返回一个对局部变量的引用 int &f() { int i = 10; return i; //错误!当函数f()返回后,i就超出了它的作用域 }在上面的函数f()中,当函数返回的时候,局部变量i就超出了它的作用域。因此,返回的对于i的引用将是没有定义的。实际上,一些编译器正是出于上述的原因而不会把函数f()编译成如代码所写的那样。然而,这种问题是间接引起的,我们必须谨慎处理应该返回对哪些对象的引用。