【C++】引用的深层理解
? ? ?
目录
? ? ? ?引用
引用
? ? 为什么会有引用及概念的由来
? ? ① 参数传递的问题
? ? ?在c语言中仅有值传递和指针传递两种方式,这两种方式在函数传参时,尤其是自定义类型的传参,暴露出一些局限性:
? ? ?值传递时会拷贝实参的副本既多占空间,又浪费时间;
? ? ?指针传递又会产生不安全的指针访问。
? ? 为解决这个问题就引入了一种新的传递方式,它本质上是指针传递,但是隐藏了间接引用运算符 “*”?,使得形参可以直接访问间接对象。
? ? ② 运算符重载的问题
? ? ?在顺序表中其赋值问题可以通过运算符重载来解决,但此时又暴露出c语言值传递和指针传递的深层问题。假设赋值运算符函数是值传递?
? ? ?void? operator=(SeqList? x,? SeqList? y); //赋值运算符函数声明
有顺序表L1 和 L2,如下图:
? ? ? ? ?
此时将L1 赋值 给 L2
? ? ? ? L2 = L1;
等价于调用赋值运算符函数语句
? ? ? ? operator = (L2, L1);
首先是将赋值语句 L2=L1 的左右操作数作为实参分别给形参x 和y 的初始化:
? ? ? ? ?SeqList? x=L2;?
? ? ? ? ?SeqList? y=L1;?
注意:此时初始化是浅拷贝,赋值运算符函数执行的是深拷贝。
? ? ?执行后结果如下图所示:? ?
? ? 可以看出,L2的size的值并没有所想的那样改为4,而x的size值却改为4,这是因为在值传递中,赋值运算符函数实现的是形参 y 给形参 x 深度赋值,而不是所需要的实参 L1 给实参 L2深度赋值。
? ? 那如果将赋值运算符函数改用指针传递
?
? ???void? operator=(SeqList? *x,? SeqList? *y); //赋值运算符重载函数声明
?
? ? 这时将 L2 = L1; 赋值语句?改为 &L2 = &L1; 赋值语句,然后左右操作数&L2和&L1作为实参分别给形参x 和y 的初始化:
? ? ?
? ? ? ? ?SeqList? *x=&L2;?
? ? ? ? ?SeqList? *y=&L1;
结果如下所示:
? ? ? ?
? 其执行的结果正是我们需要的,但是改进后的运算符语句 &L2=&L1 显然是不合法的,因为&L2是指针常量,不能是左值。
? ?若要保留赋值运算符语句的形式 L2=L1,又要实行运算符函数的指针传递,就要引入一种新的传递方式,它本质上是指针传递,但是实参隐藏了取地址符 “&”
那么,综合上面两个问题的解决方案。在指针传递中,实参和形参的关系如下:
? ? ? ? ? SeqList *? x=&L2;
? ? ? ? ? const? SeqList *? y=&L1;
? ? 要同时隐藏形参前的间接引用运算符和实参前的取地址符,而又不和值传递形式混淆,一个简便方法是去掉间接引用运算符 “*” ,把取地址运算符 “&” 移到左侧
? ? ? ? ? ??
? ? ? ? ? SeqList &? x=L2;
? ? ? ? ? const? SeqList &? y=L1;
? ? ?这种形式,左侧的 “&” 表明 x 和 y 本质上还是指针,但是间接引用对象 L1 和 L2 在传址时不再需要 “&” ,指针 x 和 y 在访问间接引用对象时也不在需要加引用运算符 “*” 。
? ? ? ? ? 这时赋值运算符函数的声明就可以是下面的形式了:
? ? ? ? ? ?void? operator = (SeqList? &x, const SeqList? &y);
? ? ??这时的实参 L2 给 L1 赋值,就是形参 x 给 y 赋值,如下所示:
? 图中左边 x 和 y (即灰色的) 在系统内部是指针,只在初始化的时候才以前置的符号表露;右侧表示在程序层面上是省略了间接引用运算符的指针。这便是引用。
引用型变量 和 const 型指针
? 引用型变量即引用,撇开内部不谈,那么所谓的引用是给已存在变量取了一个别名,这是c++对c的一个重要扩充。
? ?定义的格式为:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 类型 &? 引用型变量 = 被引用变量名;
代码如下:
? ? b是引用型变量,a是被引用的变量。有了上面的理解,引用型变量b在初始化时得到被引用变量a的指针。初始化之后,b始终表示被隐藏了间接引用运算符的间接引用表达式 *b, 使 b 在形式上成为 a 的别名,即 a 的同义词,访问 b 就是访问 a。
? ? 因为引用型变量作为隐藏的指针在初始化之后不能再被直接访问,因此也就不能被修改,? ?它实质是隐藏了间接引用运算符的 const 型指针。?
如图所示:
? ? ? ??
常引用
? ?先来看代码
? ? 因为引用型变量的实质是 const 型指针,它和const型指针一样,可以改变被引用的变量,所以不能引用 const型变量;上面代码a是const型变量,下面的引用是非法的。
? ? const型变量只能被const型引用来引用;所谓const型引用,是半隐藏的全 const 型指针,它可以引用 const 型变量,也可以引用非 const 型变量,即对被引用的变量都是 “只读” 的。
如下代码:
临时变量和const
那么如果引用型变量的类型与被引用的变量类型不一样呢,下面就来看一段代码:
这段代码编译会出错,因为两者的类型不匹配;那么修改一下代码来看一下:
此时编译通过(但可能会有警告),但不管怎样编译允许通过。
上面的一段代码报错,加了const 就可以通过是什么原因呢?下面来解释一下:
如果被引用的变量与引用的变量不匹配时,c++会创建类型正确的匿名变量(即临时变量),又临时变量具有const常属性;因为一个具有const属性的常量需要const型的引用的变量来引用,因此需要加const成为const型引用变量。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!