C++ 引用以及引用与指针的区别

概述

前面整理了指针的用法,但是经常和指针拿来对比东西是引用。确实指针在使用的过程中会有很多的麻烦,比如赋初值、使用时判空、无效指针、深浅拷贝等等。在我看来引用的指针的高级替代,它的使用规则规避了很多出错的可能。下面就对引用进行整理。

需要注意的是C11引入了右值引用,我们这里所说的引用都是在讨论左值引用

1、什么是引用?

引用是给对象起了一个别名,它也是一种复合类型。通过将声明符写成&d的形式来定义引用类型,其中d是声明的变量名。

定义引用时,程序把引用和它的初始值绑定在一起,而不是将初始值拷贝给引用。一旦初始化完成,引用将和它的初始值对象一直绑定在一起。因此引用必须初始化,而且引用不能重新绑定到另一个对象,类型要和绑定的类型一致

引用本身不是独立的数据类型,所以不占用空间,引用的地址就是对象的地址。也就无法定义指向引用的指针,无法声明存储引用类型的数组等。

int ivalue = 97;
int ivalue2 = 98;

int& refvalue = ivalue;		//refvalue是给ivalue起的的别名
refvalue = ivalue2;		//没有重新绑定,这里是赋值操作

int& refvalue2;			//编译出错,没有进行初始化 
     
int& refvalue4 = 10;		//只能绑定到对象上
int&* p = &refvalue;		//不能定义指向引用的指针

int& arr[5] = {1,2,3,4,5};	//不能定义引用数组    
int&& refvalue5 = refvalue;	//不能定义引用 引用的引用    
double& refvalue3 = ivalue;	//编译出错,类型不一致

2、引用的使用

引用跟指针很相似,使用也差不多,这里就介绍一些其中差别有点大的地方,至于细节可以去看前面整理的指针内容,只要将*改成&使用就行。

2.1、引用作为函数参数

1.当用引用作为函数的参数时,其效果和用指针作为函数参数的效果相当。当调用函数时,函数中的形参就会被当成实参变量或对象的一个别名来使用,也就是说此时函数中对形参的各种操作实际上是对实参本身进行操作,而非简单的将实参变量或对象的值拷贝给形参。

2.通常函数调用时,系统采用值传递的方式将实参变量的值传递给函数的形参变量。此时,系统会在内存中开辟空间用来存储形参变量,并将实参变量的值拷贝给形参变量,也就是说形参变量只是实参变量的副本而已;并且如果函数传递的是类的对象,系统还会调用类中的拷贝构造函数来构造形参对象。而使用引用作为函数的形参时,由于此时形参只是要传递给函数的实参变量或对象的别名而非副本,故系统不会耗费时间来在内存中开辟空间来存储形参。因此如果参数传递的数据较大时,建议使用引用作为函数的形参,这样会提高函数的时间效率,并节省内存空间

3.使用指针作为函数的形参虽然达到的效果和使用引用一样,但当调用函数时仍需要为形参指针变量在内存中分配空间,而引用则不需要这样,故在C++中推荐使用引用而非指针作为函数的参数。

4.如果在编程过程中既希望通过让引用作为函数的参数来提高函数的编程效率,又希望保护传递的参数使其在函数中不被改变,则此时应当使用对常量的引用作为函数的参数。

5.数组的引用作为函数的参数:C++的数组类型是带有长度信息的,引用传递时如果指明的是数组则必须指定数组的长度

void func(int(&a)[5])//数组引用作为函数的参数,必须指明数组的长度 
{
	sizoef(a);		//这里是20
	for(auto& i : a)
		i++;
}

int main()
{
    int number[5]={0,1,2,3,4};
    func(number); 
    return 0; 
 }

2.2、和const的使用

因为引用的定义就不能对它重新绑定,所以只有能不能通过引用修改其绑定的变量或对象。

int a=10;
const int &new_a=a;
new_a=11;		//错误!不允许通过常引用对其所绑定的变量或对象进行修改 

特别注意:

#include<iostream>
#include<string> 
using namespace std;
string func1()
{
    string temp="This is func1";
    return temp;
}
void func2(string &str)
{
    cout<<str<<endl;
}

int main()
{
    func2(func1());
    func2("Tomwenxing");
    return 0;
}

编译器时会报错:error C2664: “func2”: 不能将参数 1 从“const char [11]”转换为“std::string &”。

这是由于func1()和“Tomwenxing”都会在系统中产生一个临时对象(string对象)来存储它们,而在C++中所有的临时对象都是const类型的,而上面的程序试图将const对象赋值给非const对象,这必然会使程序报错。如果在函数func2的参数前添加const,就没问题了。

3、指针和引用的区别

  1. 引用必须初始化,指针可以不用
  2. 引用不能为空,指针可以
  3. 引用不能更换绑定对象,指针可以更换指向对象
  4. 引用不占内存,指针占用内存
  5. 不能声明引用数组,可以声明指针数组
  6. 不能引用 引用的引用(int&& b = a),可以定义指针的指针

4、总结

  1. 在引用的使用中,单纯给某个变量起别名是毫无意思的,引用的目的主要用于函数参数的传递中,解决大块数据或对象的传递效率和空间不如意的问题。
  2. 用引用传递函数的参数,能保证参数在传递的过程中不产生副本,从而提高传递效率,同时通过const的使用,还可以保证参数在传递过程中的安全性。
  3. 引用本身是目标变量或对象的别名,对引用的操作本质上就是对目标变量或对象的操作。因此能使用引用时尽量使用引用而非指针。
  4. 没有void类型的引用

感谢大家,我是假装很努力的YoungYangD(小羊)。

参考资料:
《C++ primer 第五版》
https://www.cnblogs.com/duwenxing/p/7421100.html

  • 9
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值