C++:引用详解

引用

C语言中:函数传参有传值和传址两种方式
用swap函数举例:
1.传值方式(创建了临时变量存放实参的值)
缺点:不能通过函数形参改变外部实参
优点:不能改变外部的实参

void swap(int left,int right)//此代码不能完成两数的交换
{
    int tmp = left;
    left = right;
    right = tmp;
} 

2.传址方式(创建了临时变量存放了实参的地址)
缺点:每次访问实参都要解引用
优点:可以改变外部实参

void swap(int* left,int* right)
{
    int tmp = *left;
    *left = *right;
    *right = tmp;
} 

而C++中就引入了引用的概念,下面详细介绍一下C++中的引用
上面的代码就可以写成这样
此时代码中的left和right就是实参的别名,通过交换left和right就能将传过来的实参进行交换。

void swap(int& left,int& right)
{
    int tmp = left;
    left = right;
    right = tmp;
}

一、引用的概念

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

定义引用类型的格式:
类型 & 引用变量名(对象名) = 引用实体;

void TestRef()
{
	int a = 10;
	int& ra = a;//<====定义引用类型
	printf("%p\n", &a);//-->输出10
	printf("%p\n", &ra);//ra就是a的别名,因此输出10
}

二、引用的特征

  • 引用变量的类型必须与它的实体类型一致(因为取别名要符合引用实体的身份,如果类型不一致则会报错)
  • 引用变量使用必须要进行初始化(不然没有实体都不知道给谁取别名)
  • 一个变量可以有多个引用
int a = 10;
int& ra = a;
int& rra = ra;
  • 引用一旦引用一个实体,再不能引用其他实体

三、常引用

1.引用变量

权限缩小时编译可以通过,看下方代码

int a = 10;//可读可写
const int& ra = a;//只读

权限放大时编译不能通过,看下方代码

const int a = 10;//只读
int& ra = a;//可读可写

2.引用常量

const int& ra = 10

3.类型不同时

下方代码编译时会出错,因为此时定义引用类型rd时和实体d的类型不同。

//代码编译不通过
double d = 12.14;
int& rd = d;

此时的rd和d的地址并不相同,rd的修改也不会造成d的修改,说明rd并不是d的引用,那么它引用的是谁呢???
由于类型不同,所以此时编译器会创建一个临时变量,用临时变量来进行过渡,然后把d中的整形部分拷到临时变量里,再用临时变量给rd赋值。所以这里的rd没有引用d而是引用了该临时变量。

但是奇怪的是,我们若是加上const,代码就编译通过了,这是为什么呢?

//代码编译通过
double d = 12.14;
const int& rd = d;

那么既然引用的是临时变量,那为什么要加上const???
这是因为临时变量是由编译器生成的,你不知道它的名字,也不知道它的地址,所以你不能修改它,也就是说:临时变量具有常属性。所以rd此时引用的是一个常量,那么加上const就是正确的,因此编译就通过了。

画一张图来加深理解:
在这里插入图片描述

四、引用的应用

1.做参数

把传值和传址的优点结合起来了
写起来会比较方便,同时对形参修改了会体现到我们的外部实参上(因为形参就是实参的别名),同时传引用的效率比传值的效率高,传引用写起来也比传址方便。

void swap(int& left,int& right)
{
    int tmp = left;
    left = right;
    right = tmp;
}
//函数调用
swap(10,20);

但是万一我们不想要改外面的实参,传了引用之后,在函数内部进行操作就会把实参修改怎么办?
此时就采用const引用

void testfun(const int& a)
{
    //a = 10;
    //此时a就不能改
}

所以能传引用尽量传引用,如果不让实参发生改变就加上const。

2.做返回值

加引用返回的不是临时变量,是返回值的别名。这样返回效率高。

int a;//出了作用域a还在,因此可以返回引用
int test1()//传值返回
{
	return a;//返回的是临时变量
}
int& test2()//传引用返回
{
	return a;//返回的是a的别名,不开辟空间
}

注意注意!!!

  • 如果按照引用的方式作为函数的返回值,不要返回栈上的空间。(因为当该函数调用结束之后,该函数内部创建的局部变量出了作用域会被销毁,为这个函数开辟的栈帧也会被系统回收,在调用下一个函数之前会对这一部分栈空间里的垃圾数据进行清理,因此你也会失去对这个空间的管控能力。)
  • 返回值的生命周期要不受该函数的影响—返回实体的生命周期比函数的生命周期长
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值