六一的部落格


关关难过关关过,前路漫漫亦灿灿。




绑定

将某个名字绑定到给定对象, 使用该名字即使用绑定对象

对象也称作实体

1int i = 5, &ri = i;
2cout << &i << endl << &ri << endl;  // 二者地址相同

变量

变量是具名的, 可通过变量读写对象

变量不一定拥有内存空间, 但一定对应一个明确对象:

  1. 指针本身是对象; 指针还指向另一个对象
  2. 引用是变量但不是对象; 引用绑定一个对象

变量不一定是具体类型: 引用是变量, 不是一个具体类型


指针和引用

通过指针和引用可以间接访问对象

  1. 使用类型修饰符声明引用和指针,使用基本类型描述间接访问对象的类型

    类型修饰符
    * 指针
    & 左值引用
    && 右值引用
    1T var;
    2
    3T *p = &var, &r = var;
  2. 用来间接访问对象

    • 指针对象保存所指对象的地址; 形容为指向该对象
    • 引用绑定对象, 是对象的别名; 形容为绑定该对象
  3. 指针是具体类型,引用不是

  4. 指针本身也是一个对象, 引用是一个变量


指针

是一个对象

类型修饰符 * 的前半部分描述指向的对象,后半部分描述指针

固定大小,和机器字长一致

1T var, *p = &var;    // 类型修饰符*指示p是一个指针, T为指向对象类型
2*p;                  // 返回指向对象的引用

定义空指针

空指针不指向任何对象

不允许对空指针解引用, 不允许通过空指针访问成员: 编译器会报错

1#include <cstdlib> // NULL是预处理变量,不属于命名空间std;建议避免使用
2
3int *p5 = NULL;
4int *p4 = 0; 
5int *p3 = nullptr; // 推荐使用

定义多个指针

要求基本类型一致,需要对每个指针使用类型修饰符 *

1int *ip1, *ip2;

*ip1构成一个声明符, *ip2构成另一个声明符

int是ip1和ip2共同的基本类型


取地址运算符

&

单目运算符

获取某个对象的地址


解引用运算符

*

单目运算符

获取所指对象的引用


成员访问运算符

->

双目运算符

访问所指对象的数据成员


void *指针

可以存放任意类型对象的地址

不能直接操作void *指针指向的对象,对象类型未知

1void *p;

引用

对象的别名

有两种,左值引用和右值引用

是变量, 不是对象: 不拥有内存空间

对引用读写,实则读写其绑定的对象

声明时必须显式初始化,将标识符与对象进行绑定;绑定关系不可更改

使用引用可以避免拷贝带来的开销: 调用函数时,如果 Pass-by-reference-to-const , 可以避免拷贝和修改绑定对象; 而 Pass-by-value ,会调用拷贝/移动构造函数创建实参的副本


左值引用

lvalue reference

绑定一个左值表达式

左值引用的基本类型和被绑定对象类型必须严格匹配

1T var, &refVar = var;

示例

 1#include <iostream>
 2
 3using std::cout;
 4using std::endl;
 5
 6int &fcn(int &a)
 7{
 8    return ++a;
 9}
10
11int main()
12{
13    int a = 5;
14    int &r = ++fcn(a);
15    cout << a << endl;
16    return 0;  
17}

输出

7

右值引用

rvalue reference

绑定右值表达式

接管了引用对象的资源,之后可通过右值引用对该对象进行读写


示例

 1#include <iostream>
 2
 3int fcn(int a) { return a + 1; }
 4
 5int main()
 6{
 7    int a = 5;
 8    int &&r = fcn(a);
 9    const int &cr = r; // 具有底层const的左值引用也可以绑定右值
10    r = 20;
11    std::cout << cr << std::endl;
12    return 0;
13}

指针和引用



绑定

将某个名字绑定到给定对象, 使用该名字即使用绑定对象

对象也称作实体

1int i = 5, &ri = i;
2cout << &i << endl << &ri << endl;  // 二者地址相同

变量

变量是具名的, 可通过变量读写对象

变量不一定拥有内存空间, 但一定对应一个明确对象:

  1. 指针本身是对象; 指针还指向另一个对象
  2. 引用是变量但不是对象; 引用绑定一个对象

变量不一定是具体类型: 引用是变量, 不是一个具体类型


指针和引用

通过指针和引用可以间接访问对象

  1. 使用类型修饰符声明引用和指针,使用基本类型描述间接访问对象的类型

    类型修饰符
    * 指针
    & 左值引用
    && 右值引用
    1T var;
    2
    3T *p = &var, &r = var;
  2. 用来间接访问对象

    • 指针对象保存所指对象的地址; 形容为指向该对象
    • 引用绑定对象, 是对象的别名; 形容为绑定该对象
  3. 指针是具体类型,引用不是

  4. 指针本身也是一个对象, 引用是一个变量


指针

是一个对象

类型修饰符 * 的前半部分描述指向的对象,后半部分描述指针

固定大小,和机器字长一致

1T var, *p = &var;    // 类型修饰符*指示p是一个指针, T为指向对象类型
2*p;                  // 返回指向对象的引用

定义空指针

空指针不指向任何对象

不允许对空指针解引用, 不允许通过空指针访问成员: 编译器会报错

1#include <cstdlib> // NULL是预处理变量,不属于命名空间std;建议避免使用
2
3int *p5 = NULL;
4int *p4 = 0; 
5int *p3 = nullptr; // 推荐使用

定义多个指针

要求基本类型一致,需要对每个指针使用类型修饰符 *

1int *ip1, *ip2;

*ip1构成一个声明符, *ip2构成另一个声明符

int是ip1和ip2共同的基本类型


取地址运算符

&

单目运算符

获取某个对象的地址


解引用运算符

*

单目运算符

获取所指对象的引用


成员访问运算符

->

双目运算符

访问所指对象的数据成员


void *指针

可以存放任意类型对象的地址

不能直接操作void *指针指向的对象,对象类型未知

1void *p;

引用

对象的别名

有两种,左值引用和右值引用

是变量, 不是对象: 不拥有内存空间

对引用读写,实则读写其绑定的对象

声明时必须显式初始化,将标识符与对象进行绑定;绑定关系不可更改

使用引用可以避免拷贝带来的开销: 调用函数时,如果 Pass-by-reference-to-const , 可以避免拷贝和修改绑定对象; 而 Pass-by-value ,会调用拷贝/移动构造函数创建实参的副本


左值引用

lvalue reference

绑定一个左值表达式

左值引用的基本类型和被绑定对象类型必须严格匹配

1T var, &refVar = var;

示例

 1#include <iostream>
 2
 3using std::cout;
 4using std::endl;
 5
 6int &fcn(int &a)
 7{
 8    return ++a;
 9}
10
11int main()
12{
13    int a = 5;
14    int &r = ++fcn(a);
15    cout << a << endl;
16    return 0;  
17}

输出

7

右值引用

rvalue reference

绑定右值表达式

接管了引用对象的资源,之后可通过右值引用对该对象进行读写


示例

 1#include <iostream>
 2
 3int fcn(int a) { return a + 1; }
 4
 5int main()
 6{
 7    int a = 5;
 8    int &&r = fcn(a);
 9    const int &cr = r; // 具有底层const的左值引用也可以绑定右值
10    r = 20;
11    std::cout << cr << std::endl;
12    return 0;
13}