C++引用的概念以及基本使用

引言

引用是C++的新增内容,在实际开发中会经常使用;C++用的引用就如同C语言的指针一样重要,但它比指针更加方便和易用。

我们知道,参数的传递本质上是一次赋值的过程,即将一块内存上的数据复制到另一块内存上。
对于像 char、bool、int、float 等基本类型的数据,它们占用的内存往往只有几个字节,对它们进行内存拷贝非常快速。而数组、结构体、对象是一系列数据的集合,数据的数量没有限制,可能很少,也可能成千上万,对它们进行频繁的内存拷贝可能会消耗很多时间,拖慢程序的执行效率。
C/C++ 禁止在函数调用时直接传递数组的内容,而是强制传递数组指针。而对于结构体和对象没有这种限制,调用函数时既可以传递指针,也可以直接传递内容;为了提高效率,建议传递指针。
但是在 C++ 中,我们有了一种比指针更加便捷的传递聚合类型数据的方式,那就是引用(Reference)


 一,引用的概念

引用(Reference)是 C++ 相对于C语言的又一个扩充。引用可以看做是数据的一个别名,通过这个别名和原来的名字都能够找到这份数据。引用类似于 Windows 中的快捷方式,一个可执行程序可以有多个快捷方式,通过这些快捷方式和可执行程序本身都能够运行程序;引用还类似于人的绰号(笔名),使用绰号(笔名)和本名都能表示一个人。
引用的定义方式类似于指针,只是&取代了*,语法格式为:

type &name = data;

type 是被引用的数据的类型,name 是引用的名称,data 是被引用的数据。引用必须在定义的同时初始化,并且以后也要从一而终,不能再引用其它数据,这有点类似于常量(const 变量)。

下面是一个演示引用的实例:

int main()
{
    int a = 11;
    int& b = a;//&引用定义
    cout << "a的值:" << a << "\n" << "b的值:" << b << endl;
    cout << "a的地址:" << &a << "\n" << "b的地址:" << &b << endl;//&取地址符

}

 可以看的,变量b就是变量a的引用,二者指向同一个地址,也可以说变量b是变量a的另一个名字。

需要注意的是:

  • 引用在定义时需要添加&,在使用时不能添加&,使用时添加&表示取地址。
  • 对变量b进行修改时,变量a的值也会改变。

二,引用作为函数参数(将形参和实参绑定)

引用作为函数参数时有两种原因:

  1. 在函数内部会对此参数进行修改
  2. 提高函数调用和运行效率

关于第一点:

都知道C++里提到函数就会提到形参和实参。函数的参数实质就是形参,不过这个形参的作用域只是在函数体内部,也就是说实参和形参是两个不同的东西,要想形参代替实参,肯定有一个值的传递。函数调用时,值的传递机制是通过“形参=实参”来对形参赋值达到传值目的,产生了一个实参的副本。即使函数内部有对参数的修改,也只是针对形参,也就是那个副本,实参不会有任何更改。函数一旦结束,形参生命也宣告终结,做出的修改一样没对任何变量产生影响。
例如:(对两个变量进行交换处理。此处函数的形参为p1, p2,没有引用)

void swap(int p1,int p2)
{
    int temp;
    temp = p1;
    p1 = p2;
    p2 = temp;
}
int main()
{
    int a, b;
    cin >> a >> b; //输入a,b两变量的值
    swap(a, b);//直接以变量a和b作为实参调用swap函数
    cout << a << b << endl;//输出结果
}

你会发现输出的a和b还是你输入的值,没有交换。

修改为:(对两个变量进行交换处理。此处函数的形参为p1, p2都是引用)

void swap(int &p1,int &p2)
{
    int temp;
    temp = p1;
    p1 = p2;
    p2 = temp;
}
int main()
{
    int a, b;
    cin >> a >> b; //输入a,b两变量的值
    swap(a, b);//直接以变量a和b作为实参调用swap函数
    cout << a << b << endl;//输出结果
}

再次执行,就会发现值交换了。

原理就在于采用&p1和&p2时,p1和p2是实参的别名而已,像一个指针指向实参。改变p1和p2就是改变实参的值。

关于第二点:

可以结合第一点分析,p1和p2是实参的引用,不用经过值的传递机制,已经有了实参值的信息。所以没有了传值和生成副本的时间和空间消耗。当程序对效率要求比较高时,这是非常必要的.


 拓展:

前面演示了直接转递参数,和引用传参。我们还可以用传递指针来实现。

void swap(int *p1,int *p2)
{
    int temp;
    temp = *p1;
    *p1 = *p2;
    *p2 = temp;
}
int main()
{
    int a, b;
    cin >> a >> b; //输入a,b两变量的值
    swap(&a, &b);//直接以地址作为实参调用swap函数
    cout << a << b << endl;//输出结果
}

三,引用作为函数返回值

引用除了可以作为函数形参,还可以作为函数返回值。

说明:

(1)以引用返回函数值,定义函数时需要在函数名前加&

(2)用引用返回一个函数值的最大好处是,在内存中不产生被返回值的副本。

当函数返回一个引用时,则返回一个指向返回值的隐式指针。这样,函数就可以放在赋值语句的左边。

int function1(int& aa)//以返回值的方法返回函数值
{
    return aa;
}
int& function2(int& aa)//以引用方式返回函数值
{
    return aa;
}
int main()
{
    int a = 10;
    //第一种情况,系统生成要返回值的副本(即临时变量)
   int b = function1(a);//function1()的返回值先储存在一个临时变量中,
                     //然后再把临时变量赋值给b
   //第二种情况,报错
   // function1(a) = 20;// function1()的返回值为临时变量,不能赋值(即不能为左值)
   //第三种情况,系统不会生成返回值的副本
    function2(a) = 20;//OK  此时a的值变成了20
}

说明:若函数的返回值为引用(&),则编译器就不为返回值创建临时变量了。直接返回那个变量的引用。所以千万不要返回临时变量的引用,如下:

int & function()
{
    int b = 10;
    return b;//不OK 等函数返回后,b就消失了,引用了一个消失的东西
             //程序会懵逼的。指针也一样。
}
int main()
{
    int a;
    a = function();//function()返回的东西已经消失了,引用也就不存在了
}

 

posted @ 2021-07-28 21:05  唯有自己强大  阅读(1402)  评论(0编辑  收藏  举报