【深入理解C++】引用

2023-10-30

1.变量的别名

在 C 语言中,使用指针(Pointer)可以间接获取、修改某个变量的值。在 C++ 中,使用引用(Reference)可以起到跟指针类似的功能。

引用相当于是变量的别名,一般用 & 符号表示,基本数据类型、枚举、结构体、类、指针、数组等都可以有引用。

引用必须绑定到变量上去,不能绑定到常量上去。引用指向的类型要相同。

对引用做计算,就是对引用所指向的变量做计算。

在定义的时候就必须初始化,一旦指向了某个变量,就不可以再改变,“从一而终”。

#include <iostream>
using namespace std;

int main() {
	int age = 10;
	int height = 20;

	// 定义了一个age的引用,ref相当于是age的别名
	int &ref = age;
	ref = 20;
	ref += 30;
	cout << age << endl; // 50

	ref = height;
	ref = 11;
	cout << age << endl; // 11
	cout << height << endl; // 20
	
	return 0;
}

2.变量的多个别名

可以利用引用初始化另一个引用,相当于某个变量的多个别名。

#include <iostream>
using namespace std;

int main() {
	int age = 10;

	// 定义了一个age的引用,ref相当于是age的别名
	int& ref = age;
	int& ref1 = ref;
	int& ref2 = ref1;

	ref += 10;
	ref1 += 10;
	ref2 += 10;

	cout << age << endl; // 40
	
	return 0;
}

3.引用存在的价值

不存在 “引用的引用”、“指向引用的指针”、“引用数组”。

引用存在的价值之一:比指针更安全、函数返回值可以被赋值。

举例1:通过指针传参交换两个数

#include <iostream>
using namespace std;

void swap(int *v1, int *v2) {
	int tmp = *v1;
	*v1 = *v2;
	*v2 = tmp;
}

int main() {
	int a = 10;
	int b = 20;
	swap(&a, &b);
	cout << "a = " << a << ", b = " << b << endl; // a = 20, b = 10

	return 0;
}

举例2:通过引用传参交换两个数

#include <iostream>
using namespace std;

void swap(int &v1, int &v2) {
	int tmp = v1;
	v1 = v2;
	v2 = tmp;
}

int main() {
	int a = 10;
	int b = 20;
	swap(a, b);
	cout << "a = " << a << ", b = " << b << endl; // a = 20, b = 10

	int c = 2;
	int d = 3;
	swap(c, d);
	cout << "c = " << c << ", d = " << d << endl; // c = 3, d = 2

	return 0;
}

4.引用的大小

一个引用占用一个指针的大小。

举例1:只含一个 int 整数的类对象的大小

#include <iostream>
using namespace std;

struct Student {
	int age;
};

int main() {
	cout << sizeof(Student) << endl;
	// x64(64bit): 4
	// x86(32bit): 4

	return 0;
}

举例2:只含一个 int 指针的类对象的大小

#include <iostream>
using namespace std;

struct Student {
	int *age;
};

int main() {
	cout << sizeof(Student) << endl;
	// x64(64bit): 8
	// x86(32bit): 4

	return 0;
}

举例3:只含一个 int 引用的类对象的大小

#include <iostream>
using namespace std;

struct Student {
	int &age;
};

int main() {
	cout << sizeof(Student) << endl;
	// x64(64bit): 8
	// x86(32bit): 4

	return 0;
}

5.从汇编角度看引用

引用的本质就是指针,只是编译器削弱了它的功能,所以引用就是弱化了的指针。

加断点,按 F5 进入调试,转到反汇编,不勾选“显示符号名”。

举例1:查看 int 指针的汇编代码

#include <iostream>
using namespace std;

int main() {
	
	int age = 10;

	// *p就是age的别名
	int *p = &age;
	*p = 30;

	return 0;
}

在这里插入图片描述

举例2:查看 int 引用的汇编代码

#include <iostream>
using namespace std;

int main() {
	
	int age = 10;

	// ref就是age的别名
	int &ref = age;
	ref = 30;

	return 0;
}

在这里插入图片描述

对比两图可以发现,ref 本质上就是指针,存储的就是 age 的地址值。

6.结构体的引用

#include <iostream>
using namespace std;

struct Date {
	int year;
	int month;
	int day;
};

int main() {

	Date d = { 2022, 1, 25 };
	Date& ref = d;
	ref.year = 2023;

	cout << d.year << endl; // 2023

	return 0;
}

7.指针的引用

指针是一个存放地址的变量,而指针引用指的是这个指针变量的引用。

#include <iostream>
using namespace std;

int main() {

	int age = 10;

	int *p = &age;
	int *&ref = p;
	*ref = 30;
	cout << age << endl; // 30

	int height = 40;
	ref = &height;
	cout << *ref << endl; // 40

	return 0;
}

在 C++ 中,如果参数不是引用的话,会调用参数对象的拷贝构造函数,所以如果想改变指针所指的对象(即想要改变指针里面存的地址),就要使用指针引用。

举例1:指针

#include <iostream>
using namespace std;

struct Point
{
    int x;
    int y;
};

void change1(Point* pp)
{
    pp = new Point;
    pp->x = 4;
}

int main()
{
    Point* p = new Point;
    p->x = 10;
    cout << "指针前:" << p->x << endl;
    change1(p);
    cout << "指针后:" << p->x << endl;

    return 0;
}

在这里插入图片描述

举例2:指针的引用

#include <iostream>
using namespace std;

struct Point
{
    int x;
    int y;
};

void change2(Point* &pp)
{
    pp = new Point;
    pp->x = 4;
}

int main()
{
    Point* p = new Point;
    p->x = 10;
    cout << "指针引用前:" << p->x << endl;
    change2(p);
    cout << "指针引用后:" << p->x << endl;

    return 0;
}

在这里插入图片描述

8.数组的引用

举例1:区分指针数组、数组指针、数组的引用

#include <iostream>
using namespace std;

int main() {

	int array[3] = {1, 2, 3};

	// 指针数组,数组里面可以存放3个int*
	int *arr1[3] = {array, array, array};
	
	// 数组指针,用于指向数组的指针
	int (*arr2)[3] = &array;

	// 数组的引用
	int (&ref)[3] = array;
	ref[0] = 10;
	cout << array[0] << endl; // 10

	return 0;
}

举例2:引用数组的两种格式

#include <iostream>
using namespace std;

int main() {

	// 数组名arr其实是数组的地址,也是数组首元素的地址
	// 数组名arr可以看做是指向数组首元素的指针(int *)
	int arr[] = {1, 2, 3};

	cout << *(arr + 2) << endl; // 3
	// 等价于arr[2]
	
	// 数组的引用格式1
	int (&ref)[3] = arr;
	cout << ref[2] << endl; // 3

	// 数组的引用格式2
	int * const &refArr = arr;
	cout << refArr[2] << endl; // 3

	return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【深入理解C++】引用 的相关文章

随机推荐

  • python sqlite3

    含数据库连接 表创建 增删改查 查看sqlite数据库的软件推荐使用sqlitestudio 下载地址 sqlitestudio SQLite文档类资源 CSDN下载 coding utf 8 乐乐感知学堂公众号 author https
  • SQL Server如何备份数据库

    一 首先把当前的数据库备份成一个文件 1 按照操作来 选择对应的数据库 确定备份文件的存储位置 点击确定 生成备份文件 2 然后可以通过该备份文件还原数据库 右键数据库点击还原文件和文件组 然后设置目标数据库的名字 如果数据库中已经存在相同
  • TSINGSEE青犀视频安防监控管理平台EasyNVR如何配置鉴权?

    视频监控汇聚平台EasyNVR是基于RTSP Onvif协议的视频平台 可支持将接入的视频流进行全平台 全终端的分发 分发的视频流包括RTSP RTMP HTTP FLV WS FLV HLS WebRTC等格式 为了满足用户的集成与二次开
  • Qt 串口类QSerialPort 使用笔记

    Qt 串口类QSerialPort 使用笔记 虽然现在大多数的家用PC机上已经不提供RS232接口了 但是由于RS232串口操作简单 通讯可靠 在工业领域中仍然有大量的应用 Qt以前的版本中 没有提供官方的对RS232串口的支持 编写串口程
  • virtual box安装Ubuntu操作系统

    在提供Ubuntu 18 10 Cosmic Cuttlefish映像的地址中有ubuntu 18 10 desktop amd64 iso和ubuntu 18 10 live server amd64 iso版本 它们是什么区别 简单的说
  • 机器学习——所有非支持向量的拉格朗日乘子一定为0

    问 SVM模型求解过程中所有非支持向量的拉格朗日乘子一定为0 答 正确 SVM模型的求解过程中 对于非支持向量的数据点 其对应的拉格朗日乘子为0 这是因为非支持向量数据点已经满足了约束条件 不需要对目标函数造成日对目标函数有贡献 简而言之
  • UDIMM、RDIMM和LRDIMM

    UDIMM RDIMM和LRDIMM UDIMM UDIMM 全称Unbuffered DIMM 即无缓冲双列直插内存模块 指地址和控制信号不经缓冲器 无需做任何时序调整 直接到达DIMM上的DRAM芯片 UDIMM由于在CPU和内存之间没
  • 基于python的Page Factory模式

    Pythium 基于 Python 的 Page Factory 设计模式测试库 类似于Java的Page Factory模式 旨在减少代码冗余 简单易用 具有高度的可扩展能力 支持以 annotation的方式定义元素 支持同一个元素多种
  • 【Unity 3D学习笔记】P&D 过河游戏智能实现

    P D 过河游戏智能帮助实现 实现状态图的自动生成 讲解图数据在程序中的表示方法 利用算法实现下一步的计算 对于过河游戏 首先需要知道其中各个状态之间的转换关系 绘制状态转移图如下 其中 P代表出发岸上的牧师 D代表出发岸上的恶魔 加号和减
  • 竞品分析该怎么做

    竞品分析 作用 知己知彼 百战不殆 为自身产品设计提供功能 可用性 关键技术等方面的参考 提高自身产品的差异化程度 为新立项的产品 拍脑袋想出来的 降低风险 如何选择竞品 行业内领先的产品 通常可以根据一些百度指数 行业排名 业务相似程度来
  • 四款Python在线模拟器

    一 菜鸟工具 地址 http c runoob com compile 9 打开的界面是酱紫的 左边是代码输入框 右边是结果输出框 特点 1 支持切换Python2 Python3版本 2 不支持常用导入模块 例如pandas等 3 运行速
  • 使用Python生成docx文档

    1 首先需要安装doxc的公共库 pip install python docx U 2 安装成功后 使用这个库的方法import docx 3 这样生成的docx内容会有汉字显示不出来 4 这样生成的docx会有乱码 需要调整字体格式添加
  • 解决linux磁盘空间不足的方法

    磁盘空间不足的解决办法 1 首先确定是否是磁盘空间不足 输入命令 df h 查看磁盘信息 很明显 Filesystem下的挂载点 dev vda1 下的50G容量已经耗尽 这时最简单的办法就是找到大且无用的文件并删除 首选就是log文件 2
  • Flutter 常见问题总结

    文章目录 1 内容简介 2 使用Column等容器包裹ListView报错的问题 3 Navigator operation requested does not include a Navigator 4 设置Container背景色 5
  • Java开发中使用sql简化开发

    引语 在Java开发中 我们更希望数据库能直接给我们必要的数据 然后在业务层面直接进行使用 所以写一个简单的sql语句有助于提高Java开发效率 本文由简单到复杂的小白吸收 还请多多指教 使用MySQL数据库 先创建一个简单的表 DROP
  • elemenui自己本地跑起存在的问题&做自定义组件迭代规范

    npm install安装依赖出现PhantomJS not found on PATH 问题 PhantomJS not found on PATH PhantomJS not found on PATH Downloading http
  • 在 React 中应用设计模式:策略模式

    这篇文章是关于我们许多人在 React 和前端开发中遇到的一个问题 有时甚至没有意识到这是一个问题 在不同的组件 钩子 实用程序等中实现了一段逻辑 让我们深入了解问题的详细信息以及如何解决它 正如标题所暗示的 我们将使用策略模式来解决它 问
  • react性能优化的几种方法

    react性能优化的6中方法 1 避免使用内联函数 每次render渲染时 都会创建一个新的函数实例 应该在组件内部创建一个函数 讲事件绑定到函数 这样每次调用render时 就不会创建单独的函数实例 2 使用react fragement
  • 实验五(数据结构与算法实验) 稀疏矩阵

    实验五 数据结构与算法实验 稀疏矩阵 稀疏矩阵ADT的实现 在现实应用中 一些规模很大的特殊矩阵具有重要的地位 特殊矩阵可以采用二维数组存储 简单直接 顺序存储方式保持了矩阵中元素之间的二维线性关系 矩阵操作的算法都很简单 但是其空间的利用
  • 【深入理解C++】引用

    文章目录 1 变量的别名 2 变量的多个别名 3 引用存在的价值 4 引用的大小 5 从汇编角度看引用 6 结构体的引用 7 指针的引用 8 数组的引用 1 变量的别名 在 C 语言中 使用指针 Pointer 可以间接获取 修改某个变量的