C++引用超详细介绍

引用

是C++中特有而C语言中没有的,我们知道,在C语言中,给函数传实参时,形式参数的改变不会影响原来实参的值,这里最经典的就是交换两个变量的值。

void swap (int a,int b)
{
    int c = 0;
    c = a;
    a = b;
    b = c; 
}
int main()
{
    int a1 = 2;
    int b1 = 4;
    swap(a1,b1);
    cout<<a1<<endl<<b1<<endl;
    return 0;
}

 945a3c4105a5464e86964094a69bd42d.png

这里当我们运行后就会发现a1和b1的值并没有被改变,只是形式参数a和b的值在函数体内改变了,而当函数结束后,局部变量a和b跟着也会被销毁,对于a1和b1就像什么都没有发生过一样,在C语言中,要想实际改变a1和b1的值就需要在传参时传他们的地址,也就是传指针,这样能够解决问题,

#include <iostream>
using namespace std;
void Swap(int* a, int* b)
{
	int c = 0;
	c = *a;
	a* = *b;
	b* = c;
}
int main()
{
	int a1 = 2;
	int b1 = 4;
	Swap(&a1, &b1);
	cout << a1 <<endl<< b1 << endl;
	return 0;
}

 762b51a19de643a986c7b5ac5c62b0f3.png

可是每次都传地址然后解引用略显繁琐,所以C++引入了“引用”的概念。我们先简单使用一下引用:

#include <iostream>
using namespace std;
void Swap(int& a, int& b)
{
	int c = 0;
	c = a;
	a = b;
	b = c;
}
int main()
{
	int a1 = 2;
	int b1 = 4;
	Swap(a1, b1);
	cout << a1 <<endl<< b1 << endl;
	return 0;
}

0470895ffa59466f8c580e0301f23182.png

引用的符号是&,这里与C语言中的&取地址符号相同,但是用法含义不同,要注意区分。引用简单来说就是取别名,为已存在的变量取一个别的名字,他们共同使用一块存储空间,所以在上面使用引用的例子中,传参数传的是引用,就相当于形参a是a1的一个别名,他们共同使用一块空间,对a的改变实际上也是对a1的改变,虽然在函数结束后a会被销毁,但是对a1的修改已经完成,b1相同。

引用出了做参数还可以做返回值,这也是他的重要作用之一。但是引用做返回值有很多需要注意的点,不然一不小心就会出错。如下程序:

#include <iostream>
using namespace std;
int& add(int a, int b)
{
	int c = a+b;
	return c;
}
int main()
{
	int a1 = 2;
	int b1 = 4;
	int& sum = add(a1, b1);
	cout << sum << endl;
	return 0;
}

 a9534e826f53401bb82677c78494ba38.png

这里输出了6,乍一看没问题,可是看add函数返回值是c的引用,c是一个局部变量,在函数结束时函数栈帧销毁,c也就不存在了,就会出问题,所以在不同的编译器中这里sum的值可能为6也可能随机值,因而尽量不要返回局部变量的引用。一般用引用做返回值的是静态变量或全局变量,在C++中,返回引用很好的一个引用是返回*this引用,这里涉及到类与对象中的this指针,我们先不做详细介绍,后续到类与对象模块会详细介绍this指针。

引用在使用时必须初始化,必须在一开始就与某个变量绑定,并且这种绑定形成后,就无法成为别的变量的引用,换言之,引用的指向无法改变。

int a = 0;
int &b = a;//正确
int &c = b;
//正确,此时b就是a,所以c也可以成为a的别名,此时a,b,c具有相同的含义
int d= 0;
int &b = d;
//错误,b已经是a的别名
//此时相当于对b的多次定义,是错误的

常引用

常引用是C++中一种特殊的引用类型,即被const限定的引用,他表示对一个对象的只读访问。具体看以下代码:

const int a = 0;
int& b = a;//错误,a被const限定,代表a为常量不可被修改,所以无法赋值给引用变量b

int a = 0;
const int& b = a;//正确,虽然b为常引用,但是a可以赋值给b,代表b与a 绑定,且b只能与a绑定,无法绑定其他变量
int &c = a;//正确
int &d = b;//错误,b为常引用,这里相当于常量,无法赋值给引用变量d

int &e = 0;//错误
const &f = 0;//正确,可以给常引用初始化常量初值

根据上面的例子总结下来就是,普通引用变量初始化只能赋变量(左值),而常引用变量初始化可以为变量或常量,但是之后做右值。无法再赋值给新的引用变量。

下面介绍一种特殊的情况:

int i = 0;
double j = i;
double& k = i;//错误,i类型不是int
const double& k = i;
//正确,虽然i的类型不是double,但是在这个过程中会发生类型转换
//类型转化在转化过程中会生成临时变量,而对于内置类型来说这个临时变量具有常属性
//因此可以赋值给常引用

引用和指针的区别

在表面语法上,很明显的一个语法上的区别就是引用并没有开辟新的空间,与变量共用一块储存空间,而指针开辟了新的空间来存放指针变量。(实际上从底层来说,引用变量也开辟了新的空间,只不过现在不用管它,现在就认为引用不开辟新的空间就好)

在初始化方面,无论是常引用还是普通引用,引用在创建时是一定要初始化的,不然编译通不过,而指针不强制初始化(不过注意指针不初始化容易造成野指针的问题)。因此还有一个问题,指针是有空指针NULL(nullptr)的,而引用没有空引用,在语法上不允许。

从指向上来看,指针的指向是可以改变的,可以指向不同的空间,而引用的指向一旦确定,就不允许改变。

指针有二级指针,有指向指针的指针,引用没有,没有二级引用这样的概念,只能是多个引用指向同一个变量。

对引用进行自增自减实际上就是对引用所指向的变量的自增自减,而对指针变量的自增自减会造成指向空间地址的改变(前后移动)。

关于sizeof()运算符,sizeof(指针)是指针变量本身的大小,根据系统的不同(32/64位)为4/8字节,而sizeof(引用)是引用所指向的变量的实际的大小,因为引用就是变量的别名。

从访问角度来说,我们对于引用的使用是编译器来做的,所以我们能方便的使用,无需解引用,而我们对于指针指向内容的使用需要解引用操作符*来使用,需要我们自己来控制。

总而言之,引用是C++相比较于C语言的一个改进,我们使用上的简化都是编译器在帮我们操作,是编译器承担了所有。引用相对于指针操作来说更安全一些。

最后欢迎各位朋友们在评论区交流讨论。

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值