第二章 变量和基本类型
引用
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