【C++】引用

目录

​编辑

1.引用概念

2.引用特性

2.1一个变量可以取多个别名,别名还可以取别名 

2.2一个别名不可以对应多个变量。

​编辑2.3 别名的地址一样:

2.4引用必须初始化,必须有个引用实体

2.5 引用不能改变指向

3 .引用的价值和意义

3.1.做参数 

3.2引用做参数可以提高效率

3. 3.引用做返回值

3.4 可以使用引用返回的场景:

3.5 引用做返回值提高效率 

3.6  引用做返回值可以修改返回对象

4.常引用

5.引用和指针的区别


1.引用概念

引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空 间,它和它引用的变量共用同一块内存空间。简单说引用就是取别名,比如孙悟空,齐天大圣、弼马温、猴子、美猴王都是说的孙悟空一样。

可以使用:& 来为变量取别名,,别名也是指定原来的变量只是名字不一样,可以理解为对一块空白命名为不同的名字:

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

int  a = 10;
int& x = a;

int main()
{
	int a = 1;
	int b = a;
	int& c = a;
	b++;
	printf("%d ", a);
	printf("\n");
	c++;
	printf("%d ", a);
	printf("%d ", b);
	printf("%d ", c);
	return 0;
}

2.引用特性

2.1一个变量可以取多个别名,别名还可以取别名 

2.2一个别名不可以对应多个变量。

(铜锣湾只能有一个浩南)

2.3 别名的地址一样:

2.4引用必须初始化,必须有个引用实体

int&b

2.5 引用不能改变指向

引用可以代替指针吗?

不用指针就用引用,java没有指针只有引用,但是是不可以的,c++的应用有些不一样,取别名但是别名的指向不能改变。

所以不能代替指针,比如链表中增删节点都要改变指针指向的对象也就是那个指针指向的地址,引用无法改变指向的对象所以没有办法完全代替指针。

 

3 .引用的价值和意义

3.1.做参数 

C语言中交换两个变量,需要传指针:

void Swap(int* left, int* right)
{
	int temp = *left;
	*left = *right;
	*right = temp;
}
int main()
{
	int a = 0, b = 20;
	Swap(&a, &b);
}
void Swap(int& left, int& right)
{
	int temp = left;
	left = right;
	right = temp;
}
int main()
{
	int a = 0, b = 20;
	Swap(&a, &b);
	Swap(a, b);
}

left是a的别名 right是b的别名,在链表中传二级指针的时候可以使用别名就更为简单

看一下这段教科书代码:

typedef struct SListNode
{
	struct SListNode* next;
	int val;
}SLTNode,*PSLTNode;//类型是
//第一个是将struct SListNode 重定义为 SLTNode,节点的重定义
//第一个是将 struct SListNOde * 重定义为 PSLTNode,节点指针的重定义

void SListPushBack(PSLTNode& phead, int x)//phead是plist的别名
{
	if (phead == NULL)
	{

	}
	else
	{

	}

}
int main()
{
	PSLTNode s1 = NULL;
	SListPushBack(s1, 2);
	return 0;
}

3.2引用做参数可以提高效率

#include <time.h>
struct A { int a[10000]; };
void TestFunc1(A a) {}
void TestFunc2(A& a) {}
void TestRefAndValue()
{
	A a;
	// 以值作为函数参数
	size_t begin1 = clock();
	for (size_t i = 0; i < 10000; ++i)
		TestFunc1(a);
	size_t end1 = clock();
	// 以引用作为函数参数
	size_t begin2 = clock();
	for (size_t i = 0; i < 10000; ++i)
		TestFunc2(a);
	size_t end2 = clock();
	// 分别计算两个函数运行结束后的时间
	cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;
	cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
}
int main()
{
	TestRefAndValue();

	return 0;
}

3. 3.引用做返回值

函数调用结束过后,count函数空间销毁,将n的值交给eap(寄存器)带回到ret,所以返回的不是n是n的值的拷贝。 如果要返回的值比较大,寄存器存不下的时候,就会找一块空间将这个值保存下来,这块空间不受count函数空间销毁的影响,看编译器的机制。

如果我们使用引用返回会发生什么呢?

也就是说上面的传值返回返回的是n的值的拷贝,我们使用别名作为返回值,是想返回n,

结果是不确定的,结果取决于栈帧销毁时对这块空间清理还是不清理。如果清理了就是随机值,如果不清理就是原来的值。

说明vs下没有清理,但是其他编译器就不确定了。

 

出了作用域,返回对象就销毁了,不能引用返回,否则结果不确定 

3.4 可以使用引用返回的场景:

static 修饰的全局变量 malloc上申请的变量,空间在静态区,不会销毁。

 

局部的静态全变量只初始化一次。,后面就不会执行初始化这个语句,所以分开写就会执行了。

3.5 引用做返回值提高效率 

#include <time.h>
struct A { int a[10000]; };
A a;
// 值返回
A TestFunc1() { return a; }
// 引用返回
A& TestFunc2() { return a; }
void TestReturnByRefOrValue()
{
	// 以值作为函数的返回值类型
	size_t begin1 = clock();
	for (size_t i = 0; i < 100000; ++i)
		TestFunc1();
	size_t end1 = clock();
	// 以引用作为函数的返回值类型
	size_t begin2 = clock();
	for (size_t i = 0; i < 100000; ++i)
		TestFunc2();
	size_t end2 = clock();
	// 计算两个函数运算完成之后的时间
	cout << "TestFunc1 time:" << end1 - begin1 << endl;
	cout << "TestFunc2 time:" << end2 - begin2 << endl;
}

int main()
{
	TestReturnByRefOrValue();
	return 0;
}

3.6  引用做返回值可以修改返回对象

#include<assert.h>
typedef struct SL
{
	int size;
	int* a;
}SL;

int& SLat(SL* ps, int pos)
{
	assert(ps);
	assert(pos < ps->size);
	return ps->a[pos];
}
int main()
{
	SL s;
	SLat(&s, 3) = 10;
	return 0;
}

引用:做参数,做返回值,指针也可以达到,形参修改改变形参。

4.常引用

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

a不可修改,但是b可以修改,说不过去出现了权限的放大,取别名只能平移权限不能放大权限

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

权限不可以放大但是可以缩小

int c = 10;
const int& d = c;

常量也可以取别名

const int& e = 10;

不加const就不可以,常数是常量

int i = 1;
double j = i;//隐式类型转换
double& rj = i;//不可以
//类型转换中间都会产生一个临时变量,临时变量具有常属性
const double& rj = i;//可以

 类型转换中间都会产生一个临时变量,临时变量具有常属性

这里并不是x变成无符号整型跟y比
而是生成一个临时变量,这个变量是无符号整型的x的值,再更y比

int *ptr = (int *) i;

i的类型不会变,变的是生成的临时变量。 

类型转换发生在:类型提升,类型截断

int i= 10000;

char ch = i;(发生截断),截断的也是中间生成的临时变量,临时变量具有常属性。

5.引用和指针的区别

在语法概念上来说,引用就是一个别名,没有独立空间,和引用实体共用一块空间。

但是在底层是有单独开空间的,底层引用的实现和指针是一样的。

引用方式:

指针方式:

 日常学习,我们将引用认为并没有开空间,以语法概念为准:

指针还是指针类型,引用还是原来类型。

总结来说;

  • 引用概念上定义一个变量的别名,指针存储一个变量地址。
  •  引用在定义时必须初始化,指针没有要求
  • 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何 一个同类型实体
  • 没有NULL引用,但有NULL指针
  • 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32 位平台下占4个字节)
  • 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
  • 有多级指针,但是没有多级引用
  • 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
  •  引用比指针使用起来相对更安全  

以上就是今天关于c++引用的内容,后续更详细的要到类中再为大家讲解,大家可以先点一下关注。 

  • 36
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值