--

c 语言中对于引用的一点理解



先看一段代码:

#include 
#include "stdlib.h"
using namespace std;

class Cls{
public:
  int val;
};

Cls operator+(Cls a, int val){
  Cls b;
  b.val = a.val + val;
  return b;
}

void func01(Cls a){
  cout <<"func01" << endl;
  cout "val = " << a.val << endl;
}

void func02(Cls &a){
  cout <<"func02" << endl;
  cout "val = " << a.val << endl;
}

void func03(const Cls &a){
  cout <<"func03" << endl;
  cout "val = " << a.val << endl;
}

int main(){
  Cls a;
  a.val = 4;
  
  // func01(a);
  // func01(a+2);

  // func02(a);
  // func02(a+2);

  // func03(a);
  // func03(a+2);

  return 0;
}  


当我们依次打开调用 func01, func02, func03 的时候,会发现 func01 和 func03 编译通过,输出正确,而 func02 编译出错,出错信息:
cannot bind non-const lvalue reference of type 'Cls&' to an rvalue of type 'Cls'
这是为什么?

我们知道,运算符重载,你也可以看作是一种函数调用,只不过这个函数的形式看上去像一个运算符而已,其实它就是函数调用,两个参数是 a 和 2。 运算符函数的返回值是一个 Cls 的对象。

问题在于,这个对象存放在哪里?它的生存的时间是多少?

由于我们并没有把这个返回的对象赋给某个变量,所以这是一个临时的对象。

这个临时的对象在 operator + 返回的时候生成,然后传递给func01 或者 func02 或者func03(用某种方式),然后释放掉。

具体而言,对于 func01, 传递进来的参数是传值进来的,也就是说,func01 里面的 a 和外面的临时对象不是同一个,而是复制了一份。

这个时候,哪怕外边的 临时对象被释放掉了,里面的 a 还是有效存在的。所以 func01 能够编译通过。

对于 func02 就不一样了,func02 通过引用传进来 a,函数里面的 a 和外面的临时对象其实是同一个东西。
当外面的临时对象被释放的时候,里边的 a 也就不存在了,因此编译出错。

对于 func03, 由于我们对 func03 的参数 a 采用了常量引用,而常量引用是可以绑定一个临时变量的。

请参考:
https://blog.galowicz.de/2016/03/23/const_reference_to_temporary_object/

在 the C++ Programming Language 一书中讲到:
A temporary created to hold a reference initializer persists until the end of its reference’s scope.

因此我们的 func03 函数在 cout 输出 a 的时候,这个 a 还是存在的。

有一个另外的例子,
  
int a = 1;
const double & b1 = a;
cout << "b1 = " << b1 << endl;

double & b2 = a;


这里 b1 是对的,b2 是错的。
因为把一个 int 赋值给 double,中间有一个隐式转换的过程,生成了一个临时的 double 类型的变量,b1 是对这个这个临时的 double 变量进行了引用,而不是整形变量 a 的引用。

const ref 是可以作为左值被 link 到一个临时变量的,double 不能被link 到一个临时变量。

再来做一个小练习,你觉得下面的代码会输出什么?

int a = 1;
int &b = a;
const int &c = a;
const double &d = a;
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl;
cout << "d = " << d << endl;
a = 2;
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl;
cout << "d = " << d << endl;
我跑了一下,输出是:
  
d = 1
e = 1
f = 1
d = 
e = 
f =