4_C++基础::引用

引用是C++中的一个重要特性,它是一个已存在对象的别名,用于提高效率,如在参数传递和返回值中。引用必须在声明时初始化且不能改变引用对象。传值返回会产生拷贝,而传引用返回则避免了拷贝,但可能导致作用域问题。指针和引用在内存表示上不同,引用通常用指针实现,但更安全。权限放大和缩小涉及到const引用的使用,常量引用可以接收非const对象,但反之不成立。
摘要由CSDN通过智能技术生成

4_C++基础::引用


什么是引用?

引用本质上就是取别名

例如孙悟空、美猴王、齐天大圣……

例如铁牛、黑旋风、李逵……

这些都是引用,即别名

引用需要注意什么呢?

  • 引用的实体在定义的时候必须被初始化
  • 一个引用变量引用一个实体后,不得再引用其他实体
  • 一个实体可以有多个变量引用

怎么引用呢?

类型名 & 引用变量名 = 引用实体;

ps:引用变量和引用实体必须是同一类型的!!!

int mian()
{
    int a = 0;
    int& b = a;//这里b就是a的引用
    printf("%d  %d",a,b);
    return 0;
}

引用的作用

1、做参数

a、输出型参数
void swap(int& a, int& b)
{
	int tmp = a;
	a = b;
	b = tmp;
}
int main()
{
	int a = 1;
	int b = 2;
	printf("交换前:a=%d ,b=%d\n", a, b);
	swap(a, b);
	printf("交换后:a=%d ,b=%d\n", a, b);
	return 0;
}
b、大对象传参提高效率(没有临时拷贝)

2、做返回值

a、输出型函数的返回对象
int& count(int num)
{
	static int c = 0;
    while(num >= 0)
    {
        c++;
        num++;
    }
	return c;
}
int main()
{
	std::cout << count(10) << std::endl;
	return 0;
}
b、提高效率,减少拷贝

传值返回和传引用返回

顾名思义,传值返回就是将返回值拷贝返回,传引用返回就是返回变量的引用

怎么看待传值返回和传引用返回呢?

做返回对象,以下写法对吗?

int& add(int a, int b)
{
	int c = 0;
	cout << &c <<endl;
	c = a + b;
	return c;
}
int main()
{
	int& a = add(1, 2);
	cout << &a << "     " << a << endl << endl;
	int& b = add(2, 3);
	cout << &b << "     " << b << endl << endl;
	cout << &a << "     " << a << endl << endl;
	return 0;
}

这个函数采用传引用返回:

image-20230725221448777

在第二次打印a的时候就变成了随机值?但从都到尾我们所有用到的变量都是同一块区域,这里我们可以这样理解:

image-20230725222640080

这也就是传引用的缺点。

但是传值返回呢?

image-20230726191910547

这种的返回方式就是传值返回但是会涉及到两次拷贝的问题,那我们看看传值返回和传引用返回的效率怎么样?

传引用和传值传参

#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;
}

image-20230726210502347


传值返回和传引用返回

#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()
{
	int a = 0;
	int* b = &a;//指针
	int& c = a;//引用

	cout << "&a:" << &a << endl;
	cout << "&b(指针):" << &b << endl;
	cout << "&c(引用):" << &c << endl;
	return 0;
}

image-20230726211747427

在语法角度来说,指针是重新开辟了一块空间,引用是取别名,与原变量共用一块地址空间。

image-20230726212611355

但看汇编看到指针和引用的比较,实际上是有空间的,引用的底层是用指针来实现的。


引用和指针的区别

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

权限的放大和缩小

首先,必须肯定的是const的引用只能是const int&;


权限放大

image-20230726213041044


当然,int引用可以利用const int,这里把这种叫做权限的缩小

int main()
{
    int a = 0;
    const int& b = a;//权限缩小
    return 0;
}

接下来看下面的例子

int main()
{
	int a = 0;
	double b = a;
	double& rd = a;//不合法
	const double& rrd = a;//合法
	return 0;
}

为什么double& rd = a;不合法呢?

仅仅是因为类型不同?

image-20230726220101239

所以这里的本质原因是因为类型转化产生的临时变量具有常性,而直接采用double & 来引用常性的话会涉及到权限放大,所以不合法。

由此我们在函数传参的时候为了避免这种情况的出现,统一采用const 修饰来接收传来的形参


总结

  • 引用相当于取别名,一个变量可以有多个引用,引用时必须被初始化且之后不能引用其他变量

  • 传值返回和传引用返回的区别:

    传值返回:会产生临时拷贝,影响效率

    传引用返回:不会产生临时变量,但要注意在函数在结束时作用域销毁,会清理栈帧,这种情况下不要采取传值返回

  • 指针和引用

    引用的底层也是采取指针(其余总结见上)

  • 权限的放大和缩小

    为了避免权限放大,在函数形参采用const 来进行统一修饰来接收传参


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值