【C++】引用的深层理解

发布时间:2023年12月20日

? ? ?

目录

? ? ? ?引用

为什么会有引用及概念的由来

引用型变量 和 const 型指针

常引用


引用

? ? 为什么会有引用及概念的由来

? ? ① 参数传递的问题

? ? ?在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型引用变量。


文章来源:https://blog.csdn.net/HZ_ENG/article/details/135104668
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。