news 2026/4/29 15:50:35

c++超细致讲解引用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
c++超细致讲解引用

引用的概念

引用 不是新定义一个变量,而 是给已存在变量取了一个别名 ,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。

引用的表示方法

类型 & 引用变量名 ( 对象名 ) = 引用实体;

如果熟悉C语言的同学可能会发现引用符号(&)看上去就像取地址运算符(&)或者按位AND运算符(&),其实这是一个运算符重载的例子。通过重载,同一个运算符将会有不同的含义。编译器会通过上下文来确定运算符的含义。除了这里所提到的,其实在C++中还有一些运算符重载的情况。例如:* 即表示乘法,又表示对指针的解引用操作;<<即表示插入运算符,又表示按位左移运算符等。

代码实例:

1

2

3

4

5

6

7

8

intmain()

{

//引用:取别名

inta = 10;

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

int& c = b;

return0;

}

本段代码我们可以得知,a变量取了b,c两个别名。

我们也可以通过调试观察他们的内存:

通过调取内存我们可以发现,a,b,c所指向的是同一块内存空间。

注意: 引用类型 必须和引用 实体 是 同种类型 的

引用特性

引用有三个特性,分别是:

1. 引用在 定义时必须初始化

2. 一个变量可以有多个引用

3. 引用一旦引用一个实体,再不能引用其他实体

1.引用在定义的时候必须初始化

由于引用是对已经存在的变量进行取别名,因此使用引用时必须指定变量(初始化)。

1

int& d;//错误,未初始化

2.一个变量可以有多个引用

在C++语法中,一个变量有多个引用,就类似于一个人可以有多个外号。在1.1的代码实例中变量a就有2个引用,分别是b和c。

3.引用一旦引用一个实体,再不能引用其他实体

这个也比较好理解,因为引用一旦引用了一个已经存在的实体,就是这个实体的别名,当然不能再成为其他实体的别名。

常引用与引用权限

我们来观察下面这段代码,他能编译成功吗?

1

2

3

4

5

6

7

intmain()

{

//1.

constintx = 20;

int& y = x;

return0;

}

当我们编译这段代码发现编译器报出错误警告:无法从“const int”转换为“int &”

这是因为我们在引用的时候要遵守引用的原则:

引用原则:对原变量的引用,权限不能放大。

1.3这段代码中x变量是const修饰是一个常变量,只有可读权限。而我们引用的类型是int,不仅有可读权限,还有可修改权限。这就造成了对原变量的权限放大。根据我们引用原则知道,对原变量的引用,权限是不能放大的,这就是为什么这段代码会报错的原因。

那我们再来看这一段代码,它能编译成功吗?

1

2

3

4

5

6

7

8

9

10

intmain()

{

//2.

constintx = 20;

constint& y = x;//不变

//3.

intc = 30;

constint& d = c;//缩小

return0;

}

这段代码我们发现编译成功了,我们也可以轻松地分析出这里的引用是遵守引用规则的,我们发现,权限不变或者权限缩小都是符合规则的,唯一需要注意的是:权限不能放大。

引用的使用场景

做参数

1

2

3

4

5

6

7

8

9

10

11

12

voidSwap(int& x,int& y)

{

inttmp = x;

x = y;

y = tmp;

}

intmain()

{

inta = 0, b = 1;

Swap(a, b);

return0;

}

引用可以作函数的形参,x是a的别名,y是b的别名。这里使用引用更加方便,也更好理解。

那既然以值作为函数参数和以引用作为函数参数都能解决这个问题,那为什么还要使用引用来做参数呢?这是因为引用的效率更高,我们可以通过下面这段测试代码更加直观看出效率的差别:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

#include <time.h>

structA {inta[10000]; };

voidTestFunc1(A a) {}

voidTestFunc2(A& a) {}

voidTestRefAndValue()

{

A a;

// 以值作为函数参数

size_tbegin1 =clock();

for(size_ti = 0; i < 10000; ++i)

TestFunc1(a);

size_tend1 =clock();

// 以引用作为函数参数

size_tbegin2 =clock();

for(size_ti = 0; i < 10000; ++i)

TestFunc2(a);

size_tend2 =clock();

// 分别计算两个函数运行结束后的时间

cout <<"TestFunc1(A)-time:"<< end1 - begin1 << endl;

cout <<"TestFunc2(A&)-time:"<< end2 - begin2 << endl;

}

intmain()

{

TestRefAndValue();

return0;

}

我们发现使用引用作为函数参数效率大大提高。以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。

引用做参数的意义:

1.输出型参数。

2.减少拷贝,提高效率。

做返回值

首先我们来观察这段代码的返回值是什么?

1

2

3

4

5

6

7

8

9

10

11

12

13

intCount()

{

staticintn = 0;

n++;

returnn;

}

intmain()

{

cout << Count() << endl;

cout << Count() << endl;

cout << Count() << endl;

return0;

}

这里的结果是:

1 2 3

因为n是局部静态的成员变量,只会初始化一次,虽然作用域在Count函数内部,但是生命周期是全局,我们可以通过调试观看他是否再执行函数的第一句?

传值的底层过程

传值返回这个过程当中会产生一个临时变量,跟传参一样,如果小会用寄存器替代。传值返回的类型其实是临时变量的类型,将n拷贝给临时变量,再将临时变量拷贝给ret。那么为什么要设计临时变量呢?直接把n给ret不好吗?

这是因为在当临时变量出了函数作用域之后会销毁,函数栈桢也会销毁,那么此时n是不能作为返回值再赋值给ret的。那么编译器就在此生成了一个临时变量,把n拷给临时变量,再把临时变量给ret。此时,函数栈桢销毁是不会影响临时变量的。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/29 15:49:27

Word文档合并工具:功能配置与使用指南

工具简介【Word文档合并工具】是一款面向Windows桌面的批量文档合并工具&#xff0c;主要解决将多个Word文档合并为一个文档的需求。适用于资料整理、报告编写、培训材料整理、合同处理等场景。核心功能一览功能模块具体说明批量合并支持批量合并多个Word文档为一个拖拽添加支持…

作者头像 李华
网站建设 2026/4/29 15:46:44

7 种让 iCloud 备份更快的解决方案

重要数据很容易意外丢失&#xff0c;因此定期备份 iPhone 至关重要。许多 Apple 用户依赖 iCloud 进行备份&#xff0c;但一个常见问题阻碍了他们的备份&#xff1a;iCloud 备份速度太慢。等待数小时甚至数天才能完成备份&#xff0c;实在令人沮丧。那么&#xff0c;是什么导致…

作者头像 李华
网站建设 2026/4/29 15:40:33

GLM-OCR在办公场景的妙用:快速提取图片文字,告别手动打字

GLM-OCR在办公场景的妙用&#xff1a;快速提取图片文字&#xff0c;告别手动打字 1. 办公场景中的文字提取痛点 在日常办公中&#xff0c;我们经常遇到需要从图片、PDF或扫描件中提取文字的情况。传统的手动打字方式不仅效率低下&#xff0c;还容易出错。想象一下这些场景&am…

作者头像 李华
网站建设 2026/4/29 15:39:30

python wheel

Python Wheel&#xff1a;一个被低估的打包格式 这些年见过不少团队在Python项目部署上栽跟头。有人把整个site-packages目录打包成zip&#xff0c;有人用setup.py硬扛几百兆的依赖。直到后来遇到Wheel&#xff0c;才意识到我们一直被Python包安装的笨拙程度所忍让。 1. 它是什…

作者头像 李华
网站建设 2026/4/29 15:39:30

real-anime-z新手入门实战:从部署到生成第一张动漫图

real-anime-z新手入门实战&#xff1a;从部署到生成第一张动漫图 1. 引言&#xff1a;认识real-anime-z模型 real-anime-z是一款基于Xinference部署的动漫风格图像生成模型&#xff0c;特别适合想要快速体验高质量动漫图片创作的用户。这个镜像已经预装了完整的模型服务和Gra…

作者头像 李华