首页 > 编程语言 >总结:C++引用(Reference)

总结:C++引用(Reference)

时间:2023-05-11 09:12:30浏览次数:52  
标签:返回 函数 Reference float C++ 引用 返回值 变量

声明:资料整理自网络资源,未能全部注明引用来源,如有侵权请联系。

一、基本概念

引用(Reference)是 C++ 相对于C语言的又一个扩充。 引用变量是一个别名,即某个已存在变量的另一个名字。 声明方法: 类型标识符 &引用名=目标变量名;
int a; //定义变量a
int &b = a; //定义引用b,a和b表示相同的变量,具有相同的地址
注意: 1,引用不占内存空间,必须在定义的同时初始化,且不能再引用其他数据。 2,引用在定义时需要添加&,在使用时不能添加&,使用时添加&表示取地址。  

二、应用场景

2.1 参数传递

引用变量的主要用途是用作函数的形参,按引用传递参数。 通过将应用变量用作参数,函数将使用原始数据,而不是其副本。 与复制原始结构的拷贝(按值传递)相比,使用引用可节省时间和内存; 在返回值为引用时,其效率更高,应避免返回函数终止时不再存在的内存单元引用。 将类对象传递给函数时,通常使用引用。   引用通常用于函数参数列表和函数返回值
概念描述
把引用作为参数 C++ 支持把引用作为参数传给函数,这比传一般的参数更安全。
把引用作为返回值 可以从 C++ 函数中返回引用,就像返回其他数据类型一样。

2.1.1 传引用调用

(1)传递引用给函数与传递指针的效果是一样的。这时,被调函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用,所以在被调函数中对形参变量的操作就是对其相应的目标对象(在主调函数中)的操作。 (2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给 形参分配存储单元,形参变量是实参变量的副本;如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效 率和所占空间都好。 (3)使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用"*指针变量名"的 形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰。   如果既要利用引用提高程序的效率,又要保护传递给函数的数据不在函数中被改变,就应使用常引用。

2.1.2  传常量引用调用

常引用声明方式:const 类型标识符 &引用名=目标变量名; 用这种方式声明的引用,不能通过引用对目标变量的值进行修改,从而使引用的目标成为const,达到了引用的安全性。 引用型参数应该在能被定义为const的情况下,尽量定义为const 。   总结: 1,对于小的不应被函数改变的对象,采取传值调用是合适的。 2,对于大的不应被函数改变且复制代价昂贵的对象,采取传常量调用时合适的。 3,对于所有可以被函数改变的对象,采取传引用调用时合适的。

2.3 返回值传递

要以引用返回函数值,则函数定义时要按以下格式: 类型标识符 &函数名(形参列表及类型说明) {函数体} 说明: (1)以引用返回函数值,定义函数时需要在函数名前加& (2)用引用返回一个函数值的最大好处是,在内存中不产生被返回值的副本。
#include <iostream.h>
float temp; //定义全局变量temp
float fn1(float r); //声明函数fn1
float &fn2(float r); //声明函数fn2
float fn1(float r) //定义函数fn1,它以返回值的方法返回函数值
{
 temp=(float)(r*r*3.14);
 return temp;
}
float &fn2(float r) //定义函数fn2,它以引用方式返回函数值
{
 temp=(float)(r*r*3.14);
 return temp;
}
void main() //主函数
{
 float a=fn1(10.0); //第1种情况,系统生成要返回值的副本(即临时变量)
 float &b=fn1(10.0); //第2种情况,可能会出错(不同 C++系统有不同规定)
 //不能从被调函数中返回一个临时变量或局部变量的引用
 float c=fn2(10.0); //第3种情况,系统不生成返回值的副本
 //可以从被调函数中返回一个全局变量的引用
 float &d=fn2(10.0); //第4种情况,系统不生成返回值的副本
 //可以从被调函数中返回一个全局变量的引用
 cout<<a<<c<<d;
}
引用作为返回值,必须遵守以下规则: (1)不能返回局部变量的引用。这条可以参照Effective C++[1]的Item 31。主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成为了"无所指"的引用,程序会进入未知状态。 (2)不能返回函数内部new分配的内存的引用。这条可以参照Effective C++[1]的Item 31。虽然不存在局部变量的被动销毁问题,可对于这种情况(返回函数内部new分配内存的引用),又面临其它尴尬局面。例如,被函数返回的引用只是作为一 个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成memory leak。 (3)可以返回类成员的引用,但最好是const。这条原则可以参照Effective C++[1]的Item 30。主要原因是当对象的属性是与某种业务规则(business rule)相关联的时候,其赋值常常与某些其它属性或者对象的状态有关,因此有必要将赋值操作封装在一个业务规则当中。如果其它对象可以获得该属性的非常 量引用(或指针),那么对该属性的单纯赋值就会破坏业务规则的完整性。 (4)在另外的一些操作符中,却千万不能返回引用:+-*/ 四则运算符。它们不能返回引用,Effective C++[1]的Item23详细的讨论了这个问题。主要原因是这四个操作符没有side effect,因此,它们必须构造一个对象作为返回值,可选的方案包括:返回一个对象、返回一个局部变量的引用,返回一个new分配的对象的引用、返回一 个静态对象引用。根据前面提到的引用作为返回值的三个规则,第2、3两个方案都被否决了。静态对象的引用又因为((a+b) == (c+d))会永远为true而导致错误。所以可选的只剩下返回一个对象了。  

三、注意事项

(1)在引用的使用中,单纯给某个变量取个别名是毫无意义的, 引用的目的主要用于在函数参数传递中,解决大块数据或对象的传递效率和空间不如意的问题。 (2)用引用传递函数的参数,能保证参数传递中不产生副本,提高传递的效率, 且通过const的使用,保证了引用传递的安全性。 (3)引用与指针的区别

  1,不存在空引用。引用必须连接到一块合法的内存。
  2,一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。
  3,引用必须在创建时被初始化。指针可以在任何时间被初始化。
  4,指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。程序中使用指针,程序的可读性差;
而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。
  5,选择成员的时候,引用使用点 . 来查找,而指针则使用 -> 来查找。
  6,指针可能传递一个 NULL 过来,因此在使用前必须检查有效性;引用则必然代表某个对象,不需要做此检查。

(4)使用引用的时机。 流操作符<<和>>、赋值操作符=的返回值、拷贝构造函数的参数、赋值操作符=的参数、其它情况都推荐使用引用。  

四、资料来源

数据结构与算法分析-C++语言描述(第四版) http://www.cnblogs.com/Mr-xu/archive/2012/08/07/2626973.html https://www.runoob.com/cplusplus/passing-parameters-by-references.html https://www.runoob.com/cplusplus/returning-values-by-reference.html https://book.itheima.net/course/223/1275663370879508481/1275663662815649800             <wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">        

标签:返回,函数,Reference,float,C++,引用,返回值,变量
From: https://www.cnblogs.com/bog-box/p/17389974.html

相关文章

  • 编程打卡:C++语言程序设计
    //Node.h#ifndefNODE_H#defineNODE_H//类模板的定义template<classT>classNode{private: Node<T>*next; //指向后继结点的指针public: Tdata; //数据域 Node(constT&data,Node<T>*next=0);//构造函数 voidinsertAfter(Node<T>*p); //......
  • c++打卡训练
    自守数(半成品,指没写出来,双倍给明天)流程图:伪代码:源代码:#include<iostream>usingnamespacestd;intmain(){ longinti,m; intj,n,k,a=1; for(i=0;i<=100000;i++){ n=i; m=i*i; for(j=0;n=0;j++){ n/=10; for(k=j;k>=0;k--){ a=a+a*10; if(m%a==i){ printf......
  • C++
    学生类的析构与构造#include<iostream>#include<string.h>usingnamespacestd;classStudent{public:Student(int_num,string_name,char_sex){num=_num;name=_name;sex=_sex;cout<<"Constructorcalled."......
  • httprunner 4.x学习 - 12. 测试用例引用前面一个用例testcase
    前言当登录用例写完后,后面想继续写其他用例,可以导入前面的login用例,当成下个用例的步骤使用导入前一个用例之前,需先export导出变量,变成全局变量。登录用例在testcase下新建一个test_login.yml文件,用于测试登录成功接口信息testcase/test_login.ymlconfig:name:测试登......
  • C++ 类和对象: 初始化列表
    1.回顾构造函数构造函数是6个默认的成员函数之一,完成对象初始化的工作而在构造函数中,有两种初始化对象的方式,初始化列表和函数体内赋值首先来回顾一下用函数体内赋值方法进行初始化#include<iostream>usingnamespacestd;classDate{public: Date(intyear=1,......
  • C++ return std::move(obj)的效率问题
    在visualstudio2022x32release模式下测得 直接看图即可,可以看出returnstd::move反而会降低性能,而直接返回obj则与直接构造无任何差异。这其实不符合我们对直接返回对象的直觉理解,不过这个和编译器的优化相关,可以详细搜索RVO和NRVO的相关内容。......
  • C++MFC数据库程序设计[2023-05-10]
    C++MFC数据库程序设计[2023-05-10]项目必须使用面向对象程序设计的方法来完成,项目中涉及的数据存取必须由数据库完成,同时程序必须有UI(图形或菜单均可)界面,必须完成数据录入、修改、删除、插入、浏览、查询和排序等功能。是否使用MFC中的对话框、单文档等,由同学们自行决定。即......
  • C++ 类和对象: const关键字
    1.const关键字在C语言中,const关键字用来修饰变量,表示变量的值不能被修改在C++中,const可以修饰变量,也可以用来修饰对象和类成员变量下面先来看一下,const修饰对象使用const修饰的对象d1,调用成员函数报错,这是为什么?那么只要把this指针类型改为constDate*,......
  • C++ Primer学习笔记——第二章
    第二章变量和基本类型前言数据类型是程序的基础:它告诉我们数据的意义以及我们能在数据上执行的操作。2.1基本内置类型C++定义了包括算术类型(arithmetictype)和空类型(void)在内的基本数据类型。2.1.1算术类型算术类型分为两类:整型和浮点型。具体分类:类型含义最小容......
  • mysql中删除时报错Cannot truncate a table referenced in a foreign key constraint
    在Mysql使用Truncate截断表时,提示Cannottruncateatablereferencedinaforeignkeyconstraint(monitoritem,CONSTRAINTmonitortaskpollutant_monitortask_fk)。这是因为存在外键约束导致的无法删除,我们可以先关闭外键约束,删除后再启动外键约束。1、检查外键约束SELE......