概述

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

需要注意的是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);     //这里是20for(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

C++ 引用以及引用与指针的区别相关推荐

  1. java引用和指针的区别

    Java的引用和C++的指针的区别 Java的引用和C++的指针都是指向一块内存地址的,通过引用或指针来完成对内存数据的操作,就好像风筝的线轴一样,通过线轴总是能够找到风筝,但是它们在实现,原理作用等 ...

  2. c++引用与指针的区别

    ★ 相同点: 1. 都是地址的概念: 指针指向一块内存,它的内容是所指内存的地址:引用是某块内存的别名. ★ 区别: 1. 指针是一个实体,而引用仅是个别名: 2. 引用使用时无需解引用(*),指针需 ...

  3. 2020-09-25C++学习笔记引用2:二级指针形参与指针形参的使用方法和区别重难点,主看综合代码(1、指针形参2、引用形参3、二级指针形参4、指针引用形参)

    2020-09-25C++学习笔记引用2:二级指针形参与指针引用搭配做形参的使用方法区别重难点,注意事项主看综合代码(1.指针形参2.引用形参3.二级指针形参4.指针引用形参) 1.指针引用 #inc ...

  4. 引用和指针的区别?传引用比传指针安全,为什么?如果我使用常量指针难道不行吗?

    引用和指针的区别 (1) 引用在创建的同时必须初始化,即引用到一个有效的对象:而指针在定义的时候不必初始化,可以在定义后面的任何地方重新赋值. (2) 不存在NULL引用,引用必须与合法的存储单元关联 ...

  5. 引用的定义、使用及其和指针的区别与联系

    引用 对一个数据可以建立一个"引用",它的作用是为一个变量名起一个别名. int  a; int  &b=a;//使变量b具有变量a的地址 注意: 1.引用不是一种独立的数 ...

  6. C++中 *(指针引用)与*(指针)的区别

    转自:http://blog.sina.com.cn/s/blog_673ef8130100imsp.html 指针传递参数本质上是值传递的方式,它所传递的是一个地址值.值传递过程中,被调函数的形式参 ...

  7. C++中引用传递与指针传递区别(进一步整理)

    C++中引用传递与指针传递区别(进一步整理) 博客分类: C/C++ CC++C#J#  从概念上讲.指针从本质上讲就是存放变量地址的一个变量,在逻辑上是独立的,它可以被改变,包括其所指向的地址的改变 ...

  8. C++中引用与指针的区别(详细介绍)

    转载:http://www.cnblogs.com/tracylee/archive/2012/12/04/2801519.html C++中的引用与指针的区别 指向不同类型的指针的区别在于指针类型可 ...

  9. 2-5:C++快速入门之引用,引用和指针的区别

    文章目录 (1)引用的概念 (2)引用的特点 (3)常引用 (4)引用的应用场景 A:做参数 B:做返回值 (5)引用和指针 在第一次学习C语言指针时,许多教材上都会给出一个交换两个变量值的例子,开始 ...

  10. C++中的引用与指针的区别

    C++中的引用与指针的区别 指向不同类型的指针的区别在于指针类型可以知道编译器解释某个特定地址(指针指向的地址)中的内存内容及大小,而void*指针则只表示一个内存地址,编译器不能通过该指针所指向对象 ...

最新文章

  1. 081_Introducing trigger handler class
  2. 睢县职教中心计算机专业18年高考 成绩,南模18年高考成绩喜人!想进这所学校,你需要知道这些~...
  3. android XMl 解析神奇xstream 六: 把集合list 转化为 XML文档
  4. java 内存模型 ——学习笔记
  5. Mybatis生成器插件扩展,生成findInSet方法
  6. java怎么抛出异常_java中如何抛出异常使程序不中断(7)
  7. 1003 C语言输入以某个特殊输入为结束标志
  8. ES6语法实现数据的双向绑定
  9. 发票分类代码地区代码列表
  10. 华云天下荣膺“2021年度十佳呼叫中心硬件及软件设备供应商”
  11. 使用Java写入Excel下拉选择框选项过多不显示问题
  12. 基因组选择技术在农业动物育种中的应用
  13. [源码和文档分享]基于JAVA实现的图形化页面置换算法
  14. mysql触发器——NEW与OLD解析
  15. 服务器修改密码次数过多提示被锁定,路由器密码错误次数过多锁死了怎么办?...
  16. Windows系统下的CMD Route路由配置
  17. linux 文件名带日期,在linux中追加日期到文件名
  18. Android 10.0 飞行模式下禁用NFC功能
  19. Nanopi NEO Core测试
  20. multisim变压器反馈式_Multisim在负反馈放大器性能测试中的应用

热门文章

  1. 软件工程期末复习汇总(非常详细)
  2. 树莓派python_树莓派使用Python控制LCD1602模块
  3. 专升本C语言试题分析(四)
  4. win7系统32位和64位的区别是什么32位和64位哪一个更好
  5. 谷歌、华为、腾讯等纷纷布局,代表未来游戏方向的云游戏抢滩登陆
  6. OWC11用在VB下输出统计图
  7. 《现代加工技术》第1章 绪论
  8. Djang+layui+ajax 提交表单实例
  9. 用码云搭建简单的个人个性博客
  10. 2017CBBA中国健身设备器材展览会会刊(参展商名录)