C++——引用

fe594ea5bf754ddbb223a54d8fb1e7bc.gif

目录

前言

一.引用

1.1引用概念

1.2引用特性

1.3使用场景

1.4常引用

1.5 指针与引用的区别


 

8fb442646f144d8daecdd2b61ec78ecd.png前言

本篇文章主要讲述在C++中关于引用的一些概念及其用法,还有引用与指针的些许区别,希望能够帮助大家理解~

一.引用

1.1引用概念

引用不是新定义一个变量,而是给已存在变量取了一个别名,这里我们可以理解为取外号,就比如宋江外号叫及时雨,它们二者都是指向同一个人——引用的变量也是与原变量共享一块内存空间。

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

#include <iostream>
using namespace std;

int main()
{
	int a = 1;
	int b = a;

	int& ra = a;
	printf("%p\n", &a);
	printf("%p\n", &b);
	printf("%p\n", &ra);

	return 0;
}

这里我们可以发现a与ra是共用一块内存空间的,而b则是另外开辟一处。

int main()
{
	int a = 1;
	int b = a;

	int& ra = a;
	
	ra++;
	b--;
	cout << ra << endl;
	cout << a << endl;
	cout << b << endl;
	cout << " " << endl;

	a++;
	cout << ra << endl;
	cout << a << endl;
	cout << b << endl;

	return 0;
}

从这里我们也可以看出ra++会影响到a的变化,而a++同样也会影响到ra。b只是a的拷贝,是完全独立的。

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

1.2引用特性

  • 引用在定义时必须初始化

就像你给别人取外号的前提是那个人得存在,不存在是没办法取外号的。

  • 一个变量可以有多个引用
int main()
{
	int a = 1;
	int& b = a;
	int& c = a;

	printf("%p %p %p", &a, &b, &c);
	return 0;
}
  • 引用一旦引用一个实体,再不能引用其他实体。

这里我们可以理解为引用——称号,而每一个人可以有很多种称号,但每一个称号都是唯一的,只能对应一个人。就比如弼马温,斗战胜佛,齐天大圣等等这些称号都是指向同一个人的,具有单一性。

1.3使用场景

  • 做参数
void Swap(int& left, int& right)
{
	int temp = left;
	left = right;
	right = temp;
}

int main()
{
	int a = 1;
	int b = 2;
	Swap(a, b);
	cout << a << ' ' << b << endl;

	return 0;

}

当我们的形参添加引用时Swap交换函数就发生了改变。没有引用时只是传值拷贝, 并不会真正使得外面的a与b交换。而当我们用引用来作为形参时,引用与原变量都是同一个对象,引用发生改变那么传递的变量也会发生改变。

  • 做返回值

注意:以下用例(包含错误用例)只为引出一个结论:引用返回值不适用于在栈帧中开辟的变量。

这里的返回值并不是真正的n,它在出作用域就被销毁了,所以ret接收的只是n的拷贝。

int& Count()
{
	int n = 0;
	return n;
}

int main()
{
	int ret = Count();
	cout << ret << endl;
	return 0;
}

该处返回的是n的别名(假设为temp),那么ret接收的可就是一个不确定值的n,因为在出Count函数作用域后对应的栈帧会销毁,而为n所开辟的空间我们不清楚是否也会跟着销毁,直接访问它会有风险。

这是一个有趣的例子,我们再通过ret作为n别名的别名。这样就意味着ret也指向n同处一块空间了,所以会有打印两次ret而出现3,7的情况,虽然在其中包含了空间重复利用的特点,但这种现象还是不可取的。

就比如ret目前充当的是n的通灵师,二者在进行灵魂的沟通,可就在休息一会(离开函数作用域再重新调用进入)后发现n突然性情大变(数据发生变化),那之前得到的信息又是否准确呢?

所以对处于栈帧中的变量使用引用返回本身就是不靠谱的事,要么可能被销毁返回一个随机值,要么中途多次调用导致数据变化,这些都是不稳定因素。

int& Count(int a, int b)
{
	static int c = a + b;
	return c;
}

int main()
{
	int& ret = Count(1, 2);
	cout << ret << endl; //3
	Count(3, 4);
	cout << ret << endl; //3

	return 0;
}
int& Count(int a, int b)
{
	static int c;
	c = a + b;
	return c;
}

int main()
{
	int& ret = Count(1, 2);
	cout << ret << endl; //3
	Count(3, 4);
	cout << ret << endl; //7

	return 0;
}

这里用引用返回就不会出错,因为c是在静态区所开辟的变量而非栈帧。不过为何会出现不同的值呢?因为涉及到了一个小知识点:static只会初始化一次语句(用完不会再出现)。

因此我们要想使用引用返回那就得避开栈帧,而全局,堆,静态区等都是可以引用返回的。

  • 引用返回的真正价值

通常情况下我们对一个顺序表进行修改是如下表示:这样修改是比较别扭的

而且针对每个位置的值进行++也很麻烦,但在C++中用了引用返回就很简单了~ 

而且没有引用的话那SLat(&s,3) = 10也无法执行,因为没有引用的话是传值返回,返回的是它的拷贝,而拷贝是临时对象具有常性,是没办法修改赋值的。

1.4常引用

  • 权限不能放大
int main()
{
	const int a = 10;
	int& b = a;
	return 0;
}

b无法引用由const所修饰的变量,就好比孙悟空齐天大圣,都是同一只猴呀,凭啥前者要戴上紧箍咒(const)而后者七十二般变化潇洒自在(变量)。

int main()
{
	const int a = 10;
	const int& b = a;
	return 0;
}

既然我们是同为一体的,那作为我的别名你也不能越界,你也要戴上紧箍咒,这就是权限平移

  • 权限可以缩小
int main()
{
	int a = 10;
	const int& b = a;
	return 0;
}

毕竟你只是我的别名,最大上限就是我本身,那别名稍微限制点也情有可原。

另外常引用也经常出现在类型的隐式转换中。

int main()
{
	int i = 0;
	double& j = i;
	return 0;
}

上述语句是错误的,之所以如此是因为任何类型的隐式转换都不会去改变自身类型,而是生成一个转换好类型的临时变量,而临时变量具有常性,需要在前面加上const加以修饰才可引用。

总之隐式转换要想引用的时候,const是必不可少的。

1.5 指针与引用的区别

  • 从语法上引用不需要开辟空间,而指针需要
  • 引用必须要有实体初始化,没有空引用,可以有空指针
  • 从概念上引用是对象的别名,而指针是存储变量地址
  • 从用途上引用不能任意修改指向的对象,而指针可以随意改变指向
  • 从大小上用sizeof时,引用计算的是所属类型的大小,而指针则统一是4or8字节
  • 从自增运算上引用的变量是在数值基础上自增1,而指针是跳过一个类型的大小
  • 有多级指针,无多级引用
  • 引用相对指针更安全点,使用时也不用像指针一样用*显示解引用

  • 39
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
C++中,priority_queue是一个容器适配器,用于实现优先级队列。默认情况下,priority_queue是一个大顶堆,也就是说,优先级最高的元素会被放在队列的前面。但是,我们也可以通过自定义排序规则来创建小顶堆。 在C++中,可以通过指定第三个模板参数Compare来自定义排序规则。比如,可以使用std::greater<T>来创建小顶堆,其中T是存储在priority_queue中的元素类型。例如,可以这样定义一个小顶堆的priority_queue: ```cpp std::priority_queue<int, std::vector<int>, std::greater<int>> pq; ``` 这样定义的priority_queue会根据元素的值从小到大进行排序,优先级最高的元素会被放在队列的前面。 另外,priority_queue还提供了一些成员函数来操作队列,比如empty()、size()、top()、push()、pop()等。你可以使用这些成员函数来判断队列是否为空、获取队列的大小、访问队列的第一个元素、向队列中插入元素以及移除队列中的元素。 总结起来,如果你想创建一个小顶堆的priority_queue,可以通过指定std::greater<T>作为第三个模板参数来实现。然后,你可以使用priority_queue提供的成员函数来操作队列。 #### 引用[.reference_title] - *1* [C++ STL——Queue容器、priority_queue](https://blog.csdn.net/LiuXF93/article/details/121119026)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [c++priority_queue详解](https://blog.csdn.net/qq_43679351/article/details/124825229)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值