引用不支持一般意义的赋值运算,如何理解?

C++语言 码拜 6年前 (2015-10-08) 650次浏览

C++书上讲到容器的时候,说道引用不支持一般意义的赋值运算,如何理解?另外,为什么IO库类不支持赋值和复制?

解决方案:10分
所谓“引用不支持一般意义的赋值运算”应该是用指针的观点去理解引用的说法。

考虑如下代码:

int a, b;

int &ri = a; //ri 引用a
ri = b;//ri不会引用b,而是把b的值赋值给a

int * pi = &a;//pi指向a
* pi = b;//这句是给a赋值
pi = &b;//pi改为指向b

把引用看成特殊的指针,然后用指针的观点去待引用,才有这么一种说法,因为对引用的赋值与指针完全不同……

这样反而把问题弄复杂了。引用不但“不支持一般意义的赋值运算”,而且还不支持一般意义的取地址运算”呢……

事实上,如果不把引用与指针联系起来,那么引用的这些行为很正常。引用型变量就是给变量起一个别名,对它赋值当然就等同于对原变量赋值,对它取地址也理所应当地取到原变量的地址。引用型参数就是“变量参数”,让参数成为实参变量的别名,函数内部可以通过它来改变被引用的变量。

解决方案:10分
引用只有一次初始化的机会,其他时候,都是代表所引用的对象,对引用赋值就是对引用对象的赋值。
而不是对储存引用的这个变量的地址的内容赋值;
由于引用的别名性质,虽然实现上,引用也需要一个地址存放,但是概念上引用就是所引用的对象。
所以引用的地址就是所引用的对象的地址,引用的值就是引用的对象的值;
而储存引用的那个地址(代表引用这个变量)的内容和赋值一点关系也没有;
那里只是存储了引用对象的地址,是引用初始化以后就不会改变了的;
对程序员是透明的,在语法上,概念上,是不存在的,只是出于实现引用的需要,才会为引用分配内存的。
所以简单从语法上,是没有办法,得到引用这个变量的地址的。

这个位置存储的数据,即所引用的对象地址,就是引用的地址,所以引用的值,就是所代表的变量的值。

所以存储引用这个变量的地址,就隐形了,所以引用赋值也就隐形了,被给所引用的对象赋值取代了。

解决方案:20分
int n = 10,m=11;   //一般变量定义(非引用类型)
int &ref = n; //C++引用定义,引用必须初始化,初始化后被引用的对象,就会永远保持不变。
              //C++中,ref只能引用n,不会再改为引用别的变量,比如m;
ref =m; //就是 n = m; 不是改为引用m; 
        // 引用不支持一般意义的赋值运算,如何理解?
        //就是指的这种情况吧,把如果ref是指针,ref= &m;就会指向新对象了;
        //不过这种解释很晦涩,更不好理解了。
        //  
        //这里ref 没有更换引用的目标,还是引用的n,这个赋值操作和 n=m;效果一致
        //其实就是 *(int *)&n =m;的意思;

引用的实现,就像下面的代码差不多;

//int n=10,m=11;
//int &ref = n;<==> int *const pref = &n; //ref 是 n的别名,就是 n的另一个名字    
//ref =m;      <==>   *pref =m;     <==> n=m; 
//ref++;       <==>   (*pref)++;    <==> n++;
//m =ref;      <==>    m = *pref;   <==> m = n;
//ref +=m;     <==>   (*pref)+ m;  

//下面是 引用的实现和概念的区别。
// 实现上,就是个指针常量,指针的值是被引用变量的地址;概念上是别名,是另一个变量的代表。  
//&ref<==> pref 实现上,保存了被引用变量的地址<==> &n; 概念上,因为是同一个对象,所以地址相同。
//ref<==> *pref 实现上,引用值就是地址中的值<==>    n; 概念上,因为是同一个对象,所以值也相同。

//概念上,语法上,理解引用,以及引用初始化,赋值,取地址。
int n=10,m=11;
int &ref =n;   //ref:我就是n; n:我叫n,有时别人也叫我 ref,ref是我的外号(别名);
ref = m;//ref:我就是n,给我赋值就是给n 赋值; n:ref 就是我呀,给ref赋值就是 给我赋值呀。
ref++;//ref:我就是n,我自增就是n自增; n:ref 就是我呀,ref自增就是我自增呀。
m   =ref;//ref:我就是n,我的值赋值给m,就是n的值赋值给m;
         //n:ref 就是我呀,ref的值赋值给m,就是我的值赋值给m呀;
int *p =&ref;<==> int *p=&n;//ref:我就是n,我的地址就是n的地址;
                            //n:ref 就是我呀,ref的地址,就是我的地址;

PS:
这里出现了一个问题,引用 ref 这个变量的实现,本身也需要一个地址;
但是这个地址对于我们是透明的,不是可以用正常的语法手段获取的。
我们只能够获取,这个地址里面储存的数据,即被引用的对象的地址。

这也是C++刻意这样做的,同时也是必须这样做的。

对于C++的引用,用如下语句初始化后: 
int &ref =n;

下面的恒等式,永远成立,直到其中一个结束生命周期为止:
&ref ==&n;
ref  == n; 

下面的例子,可以演示引用,取地址和取值,以及存储引用的实际地址之间的异同。

#include<iostream>
using namespace std;
struct ref_struct{
ref_struct(int &n):ref(n){};//有兴趣的话,也可以在这里输出.
public:
int &ref;
}
int main()
{
int n=10;
ref_struct r(n);

cout<<"存储引用的地址="<<&r<<",引用的地址=" << &r.ref<<",被引用对象的地址"&n<<endl; 
cout<<"引用的值="<<r.ref<<",被引用对象的值=" <<n<<endl;
return 0;
}

           


CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明引用不支持一般意义的赋值运算,如何理解?
喜欢 (0)
[1034331897@qq.com]
分享 (0)