IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 详解 C++ 引用 -> 正文阅读

[C++知识库]详解 C++ 引用

引用的概念

引用,翻译自英文 reference 。
在语法概念上讲,引用并非新定义一个变量,而是给已有变量取了一个别名,它和它引用的变量都是标识同一块内存空间,编译器并不会给引用变量开辟内存空间。也就是说,对引用操作与对变量直接操作是完全等价的。

其代码格式是:类型& 引用变量名(或对象名) = 引用实体 , 比如int& rc = c 。

打个比方,你给你的好友起了个外号,这个外号可以认为是你好友的别名。你好友的名字和别名都是指你好友,你用名字去叫他做事,他会去做事,用外号去叫他做事,他也会去做事(用外号和用名字在效果上是等价的)。

引用是已有变量的一个别名,也就是说,它的存在具有依附性,所以引用在定义时必须初始化(先有变量a,再有这个变量a的别名,也就是说别名是依附于已有实体的),而且其引用的对象在其整个生命周期中不能被改变,即引用只能依附于同一个变量,也就是说,它在初始化时就必须代表某个变量,并且在以后都表示它,不能被改变,但是一个变量可以有多个引用,就好比一个人可以有多个外号。

//这是一条错误语句,编译器在编译时就会报错,因为引用在定义时没有初始化
int& ra;

//一个变量可以有多个引用即别名
int b = 3;
int& rb = b;
int& rrb = b;
int d = 10;
//定义引用类型(rd是d的一个引用)
int& rd = d;

//打印 d变量的地址 和 rd的地址
cout << &d << endl;
cout << &rd << endl;

运行的结果是:它们两个的地址是完全一样的!

注意:引用类型必须和引用实体是同种类型,这个也很好理解。

你会误解下面这段代码吗?

//看看你是否理解到位
int x = 15;
int& r = x;

int y = 7;
r = y;

其实 r = y 这条语句的意思是:把 y 的值赋给 r (即 x )。
时刻记住:引用只是别名,而且引用只能依附于同一个变量,不能被改变。
其实如果为了更好理解的话,你把 r 全替换成 x 就好了,这样更清晰明了。
在调试状态下观察这四条语句执行完后的结果:
赋值

引用的特点
1)引用在定义时必须初始化。
2)引用一旦引用一个实体,就不能再引用其他实体。
3)一个变量可以有多个引用。

如何使用引用

1)作为参数

void Swap(int& a, int& b)
{
	int tmp = a;
	a = b;
	b = tmp;
}
void Modify(string& s)
{
	//...
}

2)作为返回值

int& func()
{
	static int n = 0;
	//...
	return n;
}
string& operator+=(char ch)
{
	//...
}

注意:如果函数返回的对象出了函数作用域后仍然存在,则可以使用传引用返回。
如果函数返回的对象在调用函数完成后被销毁,则必须使用传值返回。

像上面的 func 函数和 operator+= 函数,代码都是正确的。

来看看下面这段错误的代码:

int& Sub(int a, int b)
{
	int c = a - b;
	return c;
}

由于变量 c 的生命周期只在函数内,函数调用完成后就会被销毁,所以不应该用传引用返回,而应该用传值返回。

传引用和传值的区别

先看它们各自的特点:

传值:以值作为参数或返回值类型,在传参和返回时都会产生临时拷贝

传引用:以引用来作为参数或返回值类型,由于引用都是指已有实体,标识已有的同一块空间,故不会产生像传值那样的临时拷贝。

结论:传引用比传值的效率更高(参数或者返回值类型越大,传值传参的效率就会越低)。

引用和指针的对比

前面我们已经说过,在语法概念上讲,引用并没有自己的独立空间,它和它引用的实体是共用同一块内存空间的。

在底层实现上,使用引用也会开辟空间,这是因为引用是按照指针的方式来实现的。

int x = 4;
int& rx = x;
rx = 15;
int x = 4;
int* px = &x;
*px = 15;

让我们在VS上对这两段代码进行调试,从反汇编代码的层面上来对比引用和指针:

反汇编代码

由此,可以认为,引用在实际的底层实现方式跟指针是一样的

引用和指针总结

引用和指针的不同点
1)引用在定义时必须初始化,而指针没有这个硬性要求(但指针建议初始化,避免野指针)。
2)引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任意一个同类型的
实体。
3)没有NULL引用(有实体,才有别名),但有NULL指针。
4)在 sizeof 中含义不同:sizeof(引用)等于引用实体类型的大小,sizeof(指针)始终是指针(地址空间)的大小(32位下占 4 Byte,64位下占 8 Byte)。
5)引用的自加自减即引用实体的自加自减,指针的自加或自减即指针向后或向前偏移一个类型的大小。
6)有多级指针,但是没有多级引用。
7)访问实体的方式不同,访问引用就是访问实体,而访问指针所指的实体则需要指针显式解引用才能访问。
8)在使用时,引用相对于指针而言更加安全简便。
9)引用会进行类型检查,但指针不会进行检查(这也是为什么指针容易出现野指针和空指针的问题)。

引用和指针的关联
1)引用在实际的底层实现方式跟指针是一样的。
2)引用可以认为是 const 类型的指针(即指向已经定死,不会发生改变)。

在 C++ 中建议减少指针的使用,增加引用的使用
这是因为:在使用上,引用比指针更加方便简洁,并且引用会进行类型检查;虽然指针相对于引用更加灵活,但同时也意味着指针更不受约束,很容易出现各种问题。使用引用可以在一定程度上避免很多指针相关的问题。

理解引用时,直接从语法层面上理解即可,没有必要从底层去理解。

关于引用符号和取地址符号

int a = 9;
int& ra = a;  // 定义引用类型

int* p = &ra;  // 取ra的地址保存到指针变量p中

注意区分引用符号和取地址符号(其实也不难区分):
& 如果总是跟在类型的后面(像 double& 、int & ),那么就是引用符号,其余情况下均是取地址符号。
引用符号跟取地址符号刚好是同一个(&)而已,不要混淆。

关于为什么 C++ 的引用符号和取地址符号都是 & 的原因(个人猜测):
为了表示引用跟指针有关系,同时也为了说明 C++ 的引用符号是继承自 C 的取地址符号,所以 C++ 的引用符号才用 & 。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-12 17:14:26  更:2022-03-12 17:16:00 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 4:56:14-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码