度找详情。
注 : int &j=i; ↔int* j=&i ; 及 “ 自动解引用 ”是本文章的支柱性观点,在后边将多次提到。
再论引用(三)
Ⅲ.三个“不存在”
不存在引用的引用
不存在指向引用的指针
不存在指向引用的数组
即:
int a=3;
int& b=a;
int&& c=b; //引用的引用,不存在,注意与右值引用相区别,这里 b 为引用,可取地址,
//是左值
int&* ptr; //指向引用的指针,不存在(ptr 是一个指针,指向 int&型,正如 int* p 指向 int
//型一样)
int& arr[3]; //指向引用的数组,不存在(arr 是数组名,数组 arr 的每个元素都是 int&型
//即指向 int 型的引用)
为什么会这样?在下觉得最合理,最有说服力的解释是——C++机制问题。就像以前
在
class 中 int a=10;不可以而现在可以了一样。没准儿以后以上“三个不存在”成为“存在”也说不
定。这里我们尝试着给出现在 C++机制不允许这么做的原因。
首先,我们说,引用不是一个独立的类型,它具有依附性,而且不能为空,必须与合
法的存储单元关联。(关于引用不能为空而指针可以为空,我们在后边给出解释,见“Ⅵ .
总结与注释”注释①)抛却编译实现,仅从表面来看,引用对外极力维护其“别名”的身份。
既然要极力告诉人们“我仅仅是一个别名”,那就必须有“真身”,如果没有了“真身”,那“别
名”也自然就无从谈起。而作为“真身”(即被引用者),起码也得是一个“自由人”,而极具
依附性的“别名”引用,显然不满足这一要求,因此,它就不能被引用,即不存在引用的引
用。
另外,引用是“别名”,那么,“别名的别名”、“外号的外号”又有什么意义呢?这在日常
逻辑和一般认知中,都解释不过去。
再者,从“别名的别名”角度考虑,“引用的引用”还应该是“真身”的引用,即还应该指向
“真身”。这样,从引用的指针实现来看,外层引用的地址应该是“真身”的地址。但是,换个
角度,从“某某的引用”角度来考虑,外层引用的内容应该是内层引用的地址。这样,一旦
自动解引用,就会有两个截然不同的结果,出现明显的二义性问题,除非我们允许“引用的
引用”两次连续解引用,但回过头来想,“引用的引用”也是引用,两次自动解引用有悖于引
用的特性。
综上,无论出于以上何种理由,不允许引用的引用,是合理的。
同样,指向引用的指针也存在类似的二义性问题。再者,从引用也是用指针来实现的
角度来看,既然不允许“引用的引用”,自然也不允许指向引用的指针。由此,我们可以推
出为什么不存在指向引用的数组。因为归根到底,数组也是指针,既然不存在指向引用的
指针,自然也就不存在指向引用的数组。再者,考虑在 class 中定义数组的情况。如前所述,
引用被编译器处理为 const 的指针,而我们又知道,const 类型的变量,初始化时必须要使
用初始化列表,调用拷贝构造函数,而拷贝构造函数的形式为 T::T(const T&),如果 T 为引
用类型,那么,T&就是引用的引用,而 C++不允许引用的引用,所以,如果允许了指向引