【C++_03】引用(引用的概念、引用的操作、引用的类型、引用与函数)

引用的概念

引用是一个变量或对象的别名。当声明引用时,用一个目标对象的名字对引用作初始化,从而让引用和目标对象建立起联系,对引用的操作就是对目标对象的操作。

好比在一个班里,有个学生叫“张小明”,同时他有个绰号叫“小猪”,那么班里的同学都明白,叫“张小明”和叫“小猪”实际上都是指同一个人。引用具有类似的概念。

需要注意的是,引用必须声明时初始化(赋值)

引用的声明需要用到引用运算符“&”,其一般形式为:目标对象数据类型 &变量 = 变量;

即先写上目标对象的数据类型,然后是引用运算符“&”,接着写引用的名字。

#include<iostream>
using namespace std;

int main()
{
    int a=10;					//定义一个整型变量
    int &ra =a;					//声明对变量a的引用ra(目标对象数据类型  &变量 = 变量)

    cout<<a<<" "<<&a<<endl;     //10 0x7ff7b38a15bc
    cout<<ra<<" "<<&ra<<endl;   //10 0x7ff7b38a15bc
}

从运行结果可以看出,对引用的操作实际上就是对其引用的目标对象本身的操作,包括取引用的地址,得到的结果都是和其引用的目标对象的地址是一样的。

所以一旦声明了引用,对引用的所有操作实际上都是对其引用的目标对象的操作。

引用的操作

指针也是变量,所以也可以声明指针的引用,如下面程序中声明指针pa的引用rpa。

#include <iostream>
using namespace std;
int main()
{
    int a = 10;
    int* pa = &a;      //指向a的指针,*pa=10
    int& ra = a;       //a的引用,ra=10
    int*& rpa = pa;    //pa的引用,int*表示rpa引用的类型是整数指针,*rpa=10
    
    cout << &a << " " <<  &ra << endl;  //0x7ff7baf805ac 0x7ff7baf805ac
    cout << ra << " " << *pa << endl;   //10 10
    ra += 10;
    cout << ra << " " << *rpa << endl;  //20 20
}

下面是引用的程序示意图

  • 声明ra是a的引用, 即是变量a的一个别名。
  • 一旦ra同a的内存对象发生了联系,就不能改变。对a的访问就是对ra的访问,对ra的访问也是对a的访问。
  • 变量a和引用ra共用同一内存空间。
    在这里插入图片描述
    需要注意的是,引用运算符与地址符使用的符号相同,尽管它们显然是彼此相关的,但它们却不一样。
  • 引用运算符只在声明时使用,它放在类型名后面。(例如:int &ri = i ;)
  • 其它的”&”的使用都是地址操作符。(例如: int *ip = & i ; cout << &ip ;)

同时,为提高可读性,不应在同一行上同时声明引用、指针和变量。

引用与指针的区别

通过引用和指针,都可以操作它们所指向的目标对象,但是它们在使用上有很大的差别。这种差别主要体现在:

  • 指针是个变量,可以在程序中改变指针所指向的目标;
  • 引用是一个声明,引用不是值,不占内存空间,在声明引用时必须给它初始化,并且引用在初始化后,不可以再关联其它的目标对象。

引用的类型

声明引用时,需要指定引用的数据类型,但是并不是所有的类型都可以被引用。

  • 不能对void进行引用(因为void只是在语法上相当于一个类型,但其本质上并不是一个类型)
  • 不能对数组建立引用(因为数组名是数组空间的首地址,其本身并不是一个数据类型)
  • 不能声明引用的引用(因为引用本身不是一种数据类型,所以没有引用的引用)
  • 有空指针,但是没有空引用(例如不能这样写:int &r = NULL)
  • 可以建立指针变量的引用(如上述例子),但不能定义指向引用类型的指针变量(因为引用不是类型,是声明)

引用与函数

函数传引用是最常用的传参改变参数值方式

从下面可以看到,函数传引用也可以改变参数的值,这跟指针的作用是一样的,但却比指针更加方面,只需要在函数虚参中使用引用变量格式即可,其他都跟普通变量一样的使用。这背后是因为引用和变量共享了同一个地址空间。

#include <iostream>
using namespace std;

void swap1(int a,int b)
{
    int temp;

    temp=a;
    a=b;
    b=temp;
}

void swap2(int &a,int &b) //传引用,只是在这里加一个引用符号,其他都一致
{
    int temp;

    temp=a;
    a=b;
    b=temp;
}

int main()
{
    int n=10,m=20;
    cout<<n<<" "<<m<<endl;  //10 20
    swap1(n,m);
    cout<<n<<" "<<m<<endl; //10 20 传值不改变参数
    swap2(n,m);
    cout<<n<<" "<<m<<endl; //20 10 传引用改变参数
}

返回引用类型的函数

这部分需要理解如下代码的区别

#include<iostream>
using namespace std;

double temp; //全局变量

double fn1(double r)    //返回值,返回的是值的备份,不能修改
{
    temp = r * r * 3.14;
    return temp;
}

double& fn2(double r) {   //返回引用,可以修改
    temp = r * r * 3.14; //也可以在这里使用 static 或者 动态内存分配 做到全局
    return temp; //返回的必须是全局变量,出了函数仍在
}

int main()
{
    double a = fn1(5.0);    //返回值方式的内存布局(temp78.5作为临时变量赋值给a,a和temp完全独立)
    cout << a << endl;      //78.5
    a += 10;
    cout << a << " "<< temp << endl;  //88.5 78.5

    //double& b=fn1(5.0);   //error,返回的是局部变量的引用,编译错误(a和temp完全独立,不能进行引用)
    
    double c = fn2(5.0);    //返回引用的内存布局,修改c,不影响temp(将temp78.5写进c)
    cout << c << endl;      //78.5
    c += 10;
    cout << c << " "<< temp << endl;  //88.5 78.5

    double& d = fn2(5.0);   //返回引用的值作为引用的初始化,修改d,temp值被改变(将d作为temp78.5的别名引用)
    cout << d << endl;      //78.5
    d += 10;
    cout << d << " "<< temp << endl;  //88.5 88.5
    
    return 0;
}

关于引用与函数,上述代码已经注释得很清晰了。同时,上述代码也可以借助下面几个图进行理解。

double a = fn1(5.0); //返回值方式的内存布局
在这里插入图片描述
double &b = fn1(5.0); //返回值初始引用的内存布局,返回的是局部变量的引用,编译错误。
在这里插入图片描述double c = fn2(5.0); //返回引用的内存布局,修改c,不影响temp。

在这里插入图片描述
double &d = fn2(5.0); //返回引用的值作为引用的初始化,修改d,temp值被改变。
在这里插入图片描述

限定引用

在程序中,为保证传递的参数不被修改,可以用传递const指针或引用的方法

#include<iostream>
using namespace std;

void  fun(const int &a) //传参加const,保证不改变参数的值,也可以传const指针
{
    a += 10;
}

int main()
{
    int n=10;
    fun(n);         //error,fun函数的参数是const,不能修改
    cout<<n<<endl;
    return 0;
}

既然都是为了保证函数传参不改变参数值,那为什么不直接就使用函数传值呢?这是因为函数传值在计算机中相当于拷贝备份(例如上面例子的fun1),使用const引用可以减少拷贝,减少内存占用。

函数调用作为左值

使用引用的方法,可以将一个函数调用作为左值

我们前面讲过,函数返回引用,是有空间的,所以直接对返回的函数进行赋值。

如上述fn2的例子中,可以使用fn2(5.0) += 10,讲返回的引用作为左值,这个时候可以看到输出的temp将为88.5(78.5+10)。

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ferry_xie

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值