Reference(引用)

Posted stu-jyj3621

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Reference(引用)相关的知识,希望对你有一定的参考价值。

左值引用 

  • 引用必须在声明的时候初始化
    • int x;
      int &rx = x; //z注意这里的&位置是和int相连
      //
      int x, &rx = x;
  • 引用一旦初始化,引用名字就不能再指定给其它变量
  • 通过引用所做的读写操作实际上是作用于原变量上
    • int a{0}, b{1}; // 即int a=0;
      int &r{a};      // 引用变量 r 在声明的同时就要初始化,r是a的别名
      r = 42;         // 相当于 a = 42
      r = b;          // 相当于 a = b; 执行后 a 的值变成1
                      // 此处不是让r变成b的引用,引用r声明并初始化后,r就不能再改为其它变量的引用
      int &r2 = a;    // 继续给a起别名
      int &r3 = r;    // 声明引用变量 r3,用r初始化
                      // 这个相当于 int& r3 = a; 因为 r 是 a 的别名
      int *p = &r3    //当用&运算符获取一个引用的地址时,实际取出的是引用对应的变量的地址。p指向的是a
  • 引用可做函数参数,但调用时只需传普通变量即可,在被调函数中改变引用变量的值,则改变的是实参的值
  • 变量声明时出现的&才是引用运算符(包括函数参数声明和函数返回类型的声明),其他地方出现的&则是地址操作符。
    • int &f(int &i1, int &); //引用参数,函数返回引用
      int i;
      int &r = i;  //引用
      int *p = &i; //&取i的地址
      cout << &p;  //&取p的地址
  • 引用对应变量的左值,代表变量的内存区域,实际是一种隐式指针,但与指针存在区别
    • 指针必须通过 * 才能访问它所指向的内存单元,而引用于普通变量的访问方法差不多;
    • 指针是一个变量,它有自己独立的内存区域,但引用只是某个变量的别名,甚至没有自己独立的内存区域,必须在定义时进行初始化,并且一经定义就不能作为其他变量的引用。
  • 引用与数组。可以建立数组或数组元素的引用,但不能建立引用数组
    • int i = 0, a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, *b[10];
      int (&ra)[10];       //正确,ra是具有10个元素的整形数组的引用
      int &aa = a[0];      //正确,数组元素的引用
      int *(&rpa)[10] = b; //正确,rpa是具有10个元素的整形指针数组的引用
      int &ia[10] = a;     //错误,ia是引用数组,每个数组元素都是引用
      ra[3] = 0;           //正确,数组引用的用法
      rpa[3] = &i;         //正确
  • 引用与指针。可以建立指针的引用,但不能创建指向引用的指针
    • const char *s = "Hello"; //注意这里的const,const char*类型的值不能用于初始化char*类型的实体
      const char *&rs = s;     //无法用const char*类型的值初始化*char*&类型的引用(非常量限定)
      
      int i = 0, a[10];
      int &*ip = i; //错误,ip是指向引用的指针
      int *pi = &i;
      int *&pr = pi; //正确,pr是指针的引用

右值引用

右值引用就是绑到右值上的引用,只能绑定到即将销毁的对象上,如常量或表达式。用&&进行定义。右值引用可以方便地将引用的资源“移动”到另一个对象上。

double r = 10;
double &lr1 = r;      //正确,变量名代表左值
double &lr2 = r + 10; //错误,引用只能是变量
double &&rr = r;      //错误,变量名代表左值,而&&需要右值
double &&rr = r + 10; //正确,rr为表“r+10”计算结果,即20
    /*计算表达式“r+10”的值,结果为20,系统创建double类型的无名对象,并将20保存在该对象中,
    指定rr为该无名对象的右值引用,即无名对象的别名。假设没有右值引用,该操作是“使用无名对象的值23,用完后马上销毁该无名对象,收回它的内存区域”。如果以后要在用“r+10”,每次都重新计算
    rr遵守变量的作用域和生存期规则,在定义它的{}的作用域有效,相当于延长了无名对象的生存期*/

附上三种swap函数(分别用传值、传指针和传引用实现)

//pass by value
#include <iostream>
using std::cout;
using std::endl;
void swap(int x, int y)
{
    int t;
    t = x;
    x = y;
    y = t;
}
int main()
{
    int a = 5, b{10};
    cout << "Before: a=" << a << " b=" << b << endl;
    swap(a, b);
    cout << "After:  a=" << a << " b=" << b << endl;
    return 0;
}

技术图片

//pass by pointer
#include <iostream>
void swap(int *x, int *y)
{
    int t;
    t = *x;
    *x = *y;
    *y = t;
}
int main()
{
    int a{5}, b{10};
    std::cout << "Before: a=" << a << " b=" << b << std::endl;
    swap(&a, &b);
    std::cout << "After: a=" << a << " b=" << b << std::endl;
    return 0;
}

技术图片

//pass by reference
#include <iostream>
void swap(int &x, int &y)
{
    int t;
    t = x;
    x = y;
    y = t;
}
int main()
{
    int a{5}, b{10};
    std::cout << "Before: a=" << a << " b=" << b << std::endl;
    swap(a, b);
    std::cout << "After: a=" << a << " b=" << b << std::endl;
    system("Pause");
    return 0;
}

技术图片

以上是关于Reference(引用)的主要内容,如果未能解决你的问题,请参考以下文章

JDK 源码阅读 Reference

代码重构实战-将值对象改为引用对象(Change Value to Reference)

代码重构实战-将值对象改为引用对象(Change Value to Reference)

java 谈谈引用(强引用(Strong Reference)软引用(Soft Reference)弱引用(Weak Reference)虚引用(Phantom Reference))(示例

如何使用 Android 片段?

JDK 源码阅读 Reference