跳到主要内容

第二章 变量和基本类型

引用

int val = 1024;

// OK
int &refVal = val;

// NG:引用类型的初始值必须是一个对象
int &refVal2 = 10;

// NG:引用必须初始化
int &refVal3;

// NG:给变量引用赋值的时候不能在引用对象的基础上做计算
int &refVal4 = val + 1;

// OK:但是常量是个例外,可以在引用对象的基础上做计算。
// CPP编译器会为我们生成一个临时变量,然后将引用绑定到这个临时变量上。
const int &refVal5 = val + 1;

// NG:引用的类型必须和引用对象的类型一致
double dval = 3.14;
int &refVal6 = dval;

// OK:但是常量是个例外,引用可以绑定到一个不同类型的对象上,只要这个对象可以转换成引用的类型即可。
const int &refVal7 = dval;

指针

  • 指针的值应该属于下列4种状态之一:

    • 指向一个对象
    • 指向紧邻对象所占空间的下一个位置
    • 空指针,意味着指针没有指向任何对象
    • 无效指针,也就是上述情况之外的其他值
  • 给指针赋值,就是令它存放一个对象的地址,或者令它为空。

  • 通过*的个数可以区分指针的级别。也就是说,**表示指向指针的指针,***表示指向指针的指针的指针。

*&运算符

int i = 42;

int &r = i; // &紧随类型名出现,表示r是一个引用。
int *p; // *紧随类型名出现,表示p是一个指针。
p = &i; // &紧随在表达式后面,表示取地址符。
*p = i; // *紧随在表达式后面,表示解引用符。
int &r2 = *p; // &紧随在类型名后面,表示r2是一个引用。*紧随在表达式后面,表示解引用p。

怎么读懂复杂的指针声明

int *p;
int *&r = p

要理解r的类型到底是什么,最简单的办法是从右向左阅读r的定义。

离变量名最近的符号(此例中是&r的符号&)对变量的类型有最直接的影响,因此r是一个引用。声明符的其余部分用以确定r引用的类型是什么,此例中的符号*说明r引用的是一个指针。最后,声明的基本数据类型部分指出r引用的是一个int指针。

对于再复杂一点的定义,可以用“右左规则”来阅读。

关于右左规则(Right-Left Rule)

TODO: 有时间写一下右左规则

指向指针的引用

指针本身是一个对象,所以可以被引用。 下面来做一个指针,和指针的引用的例子。

  • 指针的引用
int i = 1024;
int newI = 2048;

int *p = &i;
int *&r = p;

r = &newI;

std::cout << *p << std::endl; // 输出 2048
  • 单纯的指针
int i = 1024;
int newI = 2048;

int *p = &i;
int *r = p; // 这里r和上面的例子不一样,它不是引用,而是指针。

r = &newI;

std::cout << *p << std::endl; // 输出 1024