C++ 左值引用
木三百川 人气:0将左值引用用于一级指针时,有以下几种用法:
//方式一:引用一级指针,常规用法 int a = 5; int * pa = &a; int * &rpa = pa; //方式二:引用指向常量的一级指针,以下几种为等效表示 int a = 5; const int * pa = &a; const int * &rpac = pa; //方式一 int const * &rpac = pa; //方式二 //方式三:引用一级指针的常引用,引用自身为常量 int a = 5; int * pa = &a; int * const &crpa = pa; //方式四:引用指向常量的一级指针,且引用自身为常量,以下几种为等效表示 int a = 5; int * pa = &a; const int * const &crpac = pa; //方式一 int const * const &crpac = pa; //方式二
在 Microsoft Visual Studio 中连续多个 const
会被编译器解释成一个,即 const const const const int *&
与 const int *&
等效,除此之外,const int const *&
在 Microsoft Visual Studio 中也与 const int *&
等效,而 int *& const
在 QT minGW 中将会报错,在 Microsoft Visual Studio 中与 int *&
等效。
各类型引用可修改属性如下表所示:
引用类型 | 修改 *rp | 修改 rp |
---|---|---|
int * &rp | 可以 | 可以 |
const int * &rp | 不可以 | 可以 |
int * const &rp | 可以 | 不可以 |
const int * const &rp | 不可以 | 不可以 |
若将变量的地址赋予引用(例如 rp=&x
),各类型引用可接受的变量地址如下表所示:
引用类型 | int变量地址 | const int变量地址 |
---|---|---|
int * &rp | 不可以 | 不可以 |
const int * &rp | 不可以 | 不可以 |
int * const &rp | 声明时可以(将创建临时变量) | 不可以 |
const int * const &rp | 声明时可以(将创建临时变量) | 声明时可以(将创建临时变量) |
若将一级指针变量赋予引用(例如 rp=p
),各类型引用可接受的一级指针变量如下表所示。若赋值时等号右边是函数返回的临时指针变量(属于右值),则只有当等号左边为 int * const &
以及 const int * const &
类型时不会报错,此时必会创建临时变量(与 const
左值引用性质一致)。
引用类型 | int *变量 | const int *变量 | int * const变量 | const int * const变量 |
---|---|---|---|---|
int * &rp | 可以 | 不可以 | 不可以 | 不可以 |
const int * &rp | 不可以 | 可以 | 不可以 | 不可以 |
int * const &rp | 声明时可以 | 不可以 | 声明时可以 | 不可以 |
const int * const &rp | 声明时可以(将创建临时变量) | 声明时可以 | 声明时可以(将创建临时变量) | 声明时可以 |
若将引用变量赋予引用(例如 rp=rp2
),各类型引用可接受的引用变量如下表所示。比较上下两表可知,左值引用类型变量被初始化完毕后,若要将其赋值给另一引用变量,赋值时的表现与所引用类型的变量相一致。
引用类型 | int *&变量 | const int *&变量 | int * const&变量 | const int * const&变量 |
---|---|---|---|---|
int * &rp | 可以 | 不可以 | 不可以 | 不可以 |
const int * &rp | 不可以 | 可以 | 不可以 | 不可以 |
int * const &rp | 声明时可以 | 不可以 | 声明时可以 | 不可以 |
const int * const &rp | 声明时可以(将创建临时变量) | 声明时可以 | 声明时可以(将创建临时变量) | 声明时可以 |
补充:C++ (左值)引用和指针简介
1. 引用
引用(reference):引用指向一个左值,并一直与指向的左值绑定(bind)在一起。用《C++ Primer》里面的话说,引用就是“给对象起了另外一个名字”
int ival = 1024; int &refVal = ival; // refVal引用ival
引用必须被初始化:引用被声明后必须被立刻初始化,否则就会报错
int ival = 1024; int &refVal = ival; // 顺利引用 int &refVal2; // 报错,因为没有初始化
引用无法更改指向的左值:引用一旦经过初始化绑定后,就无法更改绑定的对象
引用不是对象:引用只是一个对象的别名,自身不是对象。你对引用的赋值,取值实际上等于对其引用的对象的赋值,取值
int ival = 1024; int &refVal = ival; refVal = 2; // 等于对ival赋值 int ii = refVal; // 等于将ival的值赋给ii
一个对象多个引用:这是允许的,一个对象可以拥有多个”别名“
int ival = 1024; int &refVal = ival; int &refVal2 = ival; // refVal2作为ival的第二个引用
2. 指针
指针(Pointer):指针用于存储一个对象的地址,我们称为“指向”某个对象。通过指针,我们可以访问到对象在内存空间中的地址以及对象本身存储的值
int *p; // 定义一个指针
2.1. 获取地址与访问对象
利用指针获取对象地址:由于指针本身是“存储地址的对象”,我们不能直接让指针存储对象本身,这时候就需要用取地址符(&)来提取对象的地址
int ival = 42; int *p = &ival; // 让指针p指向ival的地址
利用指针访问对象:直接访问指针的话,得到的是地址。要访问实际对象,就要用到解引用符(*)。解引用只适用于指向某个对象的有效指针
int ival = 42;
int *p = &ival;
int ival2; // 新定义整数类型变量ival2
ival2 = *p; // 将ival2赋值为p指向的值(也就是ival的值)
2.2. 指针的特殊状态
空指针(Null Pointer):一个值为0,不指向任何对象的指针
// 以下三行代码本质相同,都是初始化一个空指针 int *p1 = nullptr; int *p2 = 0; int *p3 = NULL;
未初始化的指针:未指向任何地址,并且也不是空指针的指针是忌使用的。这样的指针由于指向的位置不确定,访问时有可能会造成未定义行为(Undefined Behaviour)。所以在定义指针时,一定要进行初始化,即便现在不会立刻使用,也要初始化为空指针
2.3 void* 指针
void类型:void被称之为“空类型”,它一般被用与没有返回值的函数上。
void*指针:一个void类型的指针同样能指向一块内存地址,但因为类型是空,我们没有办法知晓指向的类型,以至于不知道该类型占用的内存大小,因此无法访问指向的对象本身。
3. 引用和指针的复合使用
引用的引用:不合法。因为引用本身不是对象,所以无法使一个引用绑定另一个引用
引用的指针:不合法。因为引用本身不是对象,所以无法使一个指针指向一个引用
指针的引用:合法。指针本身是对象,引用可以绑定指针
int i = 42; int *p = &i; int *&r = p; // r引用指针p
指针的指针:合法。指针本身是对象,指针可以指向指针
int i = 42; int *p = &i; // p指向i int **p2 = &p; // p2指向p std::cout << **p2 << std::endl; // 两次解引,输出“42”
加载全部内容