目录

1.什么是引用

2.引用的定义

 3.引用的特性

4.引用的使用

4.1引用传参

4.2传引用返回

5.const引用(在引用的定义前用const修饰)

5.1对于引用

5.2对于指针

6.引用&指针

总结


1.什么是引用

引用就是给变量起别名,一个变量可以有多个别名,引用变量不会另辟空间,语法上和被引用的变量公用同一块空间,就像一个人可以有多个称号,所有称号都是再说一个人。

2.引用的定义

类型& 引用别名 =被引用对象;

 3.引用的特性

  • 引用在定义时必须初始化
  • 一个变量可以有多个引用
  • 引用一旦引用一个实体就不能再引用其他实体
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
int main()
{
	const char* jjxt= "帅哥";
	const char*& x = jjxt;
	const char*& bozhu = jjxt;

	int a = 1;
	int& b = a;
	int& c = b;


	cout << jjxt << endl;
	cout << xxj << endl;
	cout << bozhu << endl;//const修饰的字符串没法修改

	cout << a << endl;
	cout << b << endl;
	cout << c << endl;

	++b;//因为本质是同一块空间里的同一个数据,一变全变
	cout << a << endl;
	cout << b << endl;
	cout << c << endl;

	return 0;
}

 

4.引用的使用

引用主要被用于引用传参和做返回值时减少拷贝提高效率,和改变引用对象同时改变被引用对象(功能类似指针)在c++中大部分地方我们用引用代替指针,但是少部分地方任然离不开指针(比如链表,因为引用无法改变指向)

归根结底是因为引用对和被引用对象公用同一空间 。

4.1引用传参

void Swap(int* rx, int* ry)
{
	int tmp = *rx;
	*rx = *ry;
	*ry = tmp;
}

void Swap(int& rx, int& ry)
{
	int tmp = rx;
	rx = ry;
	ry = tmp;
}

swap是典型的传址调用函数,可以用传引用代替。

4.2传引用返回

int& func1()
{
	int ret = 0;
	return ret;  
}
int main()
{
	int& x = func1();
	cout << x << endl;
	return 0;
}

ret在函数栈帧销毁时,空间已经被系统回收,该空间是否被覆盖(被用于存放其他内容)是未知的,取决于编译器,该函数的返回值是一个ret的一个引用,可以理解为系统给了一个临时的引用变量int& tmp = ret,而引用x又对tmp进行引用,也就是说x和被销毁的ret公用一个空间,这是危险的,毕竟我们不知道ret被销毁后,原空间是什么状态。

运行结果:

int& func1()
{
	int ret = 0;
	return ret;  
}
int& fun2()
{
	int y = 123;
	return y;
}
int main()
{
	int& x = func1();
	cout << x << endl;
	fun2();
	cout << x << endl;
	return 0;
}

 当我们创建于func1几乎相同的,在vs环境中,编译器将原来用于func1的函数栈帧空间分配给func2,导致原来局部变量ret使用的空间被覆盖,此时再通过别名来访问这个空间,就会发现期望的x值已经发生改变。

上述情况是基于被引用对象随着函数栈帧销毁而销毁的情况,这种情况不推荐使用传引用返回,那么反之,当被引用对象不会随着函数栈帧的销毁而销毁时,传引用返回的使用就会使函数更加便捷和灵活,我们推荐使用传引用返回。

对于顺序表中,查找和修改指定位置的函数,利回就用传引用返能合二为一

这时SLat函数独自就能完成读写的操作。 

5.const引用(在引用的定义前用const修饰)

被const修饰的对象具有常性,只能读,不能写,也就是访问权限缩小(一般权限的放大缩小是对引用和指针来说的)

对于const修饰的对象,必须用const引用 

对于普通对象,const引用也能引用

这是因为,访问权限在引用的过程中只能缩小不能放大

5.1对于引用

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

       这里就会报错,权限被放大了。

5.2对于指针


int main()
{
	const int a = 0;
	int& ra = a;


	int b = 0;
	const int* p = &b;
	int* p2 = p;
	return 0;
}

指针的访问权限被放大,所以报错。(这里多提一点,被const修饰的指针,是它指向的变量具有常性,而不是指针本身具有常性)。

综上所述,我们可以知道,在用引用传参是尽量加上const,这样不管被引用对象是否被const修饰,都可以进行传参。

5.3类型转换中的常性

和函数返回时,产生临时变量一样,类型转换也会产生临时变量。

产生的临时变量为指定的类型且具有常性的。而跨类型引用本质上是对临时变量的引用

int main()
{
	int i = 0;
	double& ri = i;
	int i = 0;
	const double& ri = i;
}

这里的引用,本质上是对具有常性double类型的临时变量的引用。

6.引用&指针

  • 语法概念上,引用是给一个变量取别名,不开新空间,指针是直接创建一个指针变量来存地址,需要开辟空间。
  • 语法上,引用在定义时就要初始化,指针在语法上不强求。
  • 引用一旦确定被引用对象就不能更改,指针可以不断改变指向的对象。
  • 引用可以直接访问被引用对象,而指针需要解引用。
  • sizeof的含义不同,引用是被引用对象的类型大小,指针是地址所占字节个数,32位是4,64位是8。
  • 指针很容易出现野指针问题,引用相对安全一些。

二者在实践中有重叠性,但又各有千秋,它们相辅相成,互相不可完全替代。

总结

基本概念
引用是为变量创建的别名,与被引用变量共享内存空间。一个变量可拥有多个引用

核心特性
1. 必须初始化
2. 可多级引用(一个变量多个别名)
3. 一旦绑定实体后不可更改引用对象

主要用途
1. 函数参数:替代指针实现传址调用,更安全简洁
2. 返回值:避免拷贝开销,但需注意返回局部变量引用的风险

const引用
遵循"权限不放大"原则:const对象必须用const引用,普通对象可用const引用
类型转换时会生成具有常性的临时变量

与指针对比
1. 内存:引用不占额外空间,指针需要存储地址
2. 安全性:引用更安全,不存在野引用问题
3. 灵活性:指针可重定向,引用一旦绑定不可更改
4. 访问方式:引用直接访问,指针需解引用

本质区别:引用是语法层面的别名机制,指针是底层的内存地址操作。两者在C++中互补使用,各有适用场景

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐