复合类型--引用与指针
2.3.1 引用(reference)
引用必须初始化,一旦初始化完成,引用将与它的初始值对象绑定(bind)在一起。引用只能绑定一次,且只能绑定在对象上,因而初始值必须是一个对象。
int &refVal; //错误,引用必须初始化
int &refVal = 10; //错误,引用不能绑定在字面量上
除了两种例外情况,引用的类型要和与之绑定的对象严格匹配。
double dVal = 3.14;
int &refVal1 = dVal; //错误,此处引用类型的初始值必须是一个int型对象
例外1:const的引用的初始化可以是任意表达式;
引用的实质:
引用并非对象,它只是为一个已经存在的对象起了另外一个名字,所以无法定义引用的引用。
通常我们使用引用时,指的是左值引用(lvalue reference)。
2.3.2 指针(pointer)
指针与引用均可以间接访问对象,但不同的是:
1.指针本身就是一个对象,它可以先后指向不同的对象;
2.指针无须在定义时赋值。与其它内置类型一样,在块作用域内定义的指针如果没有被初始化,也将拥有一个不确定的值。
除了两种例外情况,其他所有指针的类型都要和它所指的对象严格匹配。
例外1:允许令一个指向常量的指针(pointer to const)指向一个非常量的对象;
空指针的生成方法:
int *p1 = nullptr; //C++11引入的一种方法,等价于 int *p1 = 0; int *p2 = 0; //直接将p2初始化为字面常量0,注意,它不同于int型的0 int *p3 = NULL; //等价于 int *p3 = 0; //NULL为预处理变量(preprocessor variable),它由预处理器负责管理。预处理器是运行于编译过程之前的一段程序。 //当遇到预处理变量时,预处理器会自动地将它替换为实际值。如#include 指令,#ifndef...#endif指令也要经过预处理过程
可以直接将地址的字面量值赋给指针吗?
int *pi = 0040FA68; //Error C3688 invalid literal suffix 'FA68'; literal operator or literal operator template 'operator ""FA68' not foun
2.4 const限定符
与引用的绑定类似,const对象一旦创建后其值就不能再改变,所以const对象必须初始化。
const的工作实质:编译器在编译的过程中,把用到const常量的地方全部换成相应的值。
const int bufSize = 512;//编译器会找到所有用到bufSize的地方,然后用512代替
默认状态下,const对象仅在本文件内有效。如果想在多个文件中共享const对象,则不管声明还是定义都需要加上关键字extern
//file_1.cpp定义并初始化了一个常量,该常量能被其他文件访问 extern const int bufSize = fcn(); //file_1.h头文件 extern const int bufSize; //与file_1.cpp中的bufSize是同一个
2.4.1 const的引用(reference to const)(并不是一个好名字,因为让人误以为是const型变量的引用,然而const只是“对引用可参与的操作做出了限制”,对于引用的对象本身是不是一个常量未作限定)(“对引用可参与的操作做出了限制”:指不能直接通过给引用赋新的值来改变引用的值,但可以通过改变被绑定对象的值来间接改变引用的值)
与普通引用不同的是,对const的引用不能被用来修改被绑定的对象的值。
const int i = 10; int &r1 = i; //r1是普通引用 const int &r2 = i; //r2是const的引用 r1 = 11; //正确 r2 = 11; //错误,不能通过const的引用来修改被绑定的对象的值。
在初始化常量引用时,允许用任意表达式作为初始值。
int i = 42; const int &r1 = i; //允许将const int&绑定到int上 const int &r2 = 42; //允许用字面量进行初始化 const int &r3 = r1*2; //正确 int &r4 = r1*r2; //错误
下面设置四组对照试验,特别注意第1和第3个实验结果:
int i = 10; //实验一 const int &r1 = i;// r1 = 10; i=11; //r1的值改变 r1 = 11; const int i = 10;//实验二 const int &r2 = i; //r1 = 10; i=11; //无法赋值给i //Error (active) expression must be a modifiable lvalue double d = 10.1;//实验三 const int &r3 = d; //loss of data,r3 = 10; d=11.0; // r3的值不变 r3 = 10; const double d = 10.1;//实验四 const int &r4 = d; //loss of data,r4=10; d=11.0; //无法复制给d //Error (active) expression must be a modifiable lvalue
我们有可能会认为“对const的引用不能被用来修改被绑定的对象的值”,“是因为有const的限定,const的引用本身就是一个常量,无法再更改其值”。然而,由实验1可知,r1的值是可以改变的。所以不能因为有 const修饰 就认为是常量。
实验3的结果之所以不变,是因为此时的r3绑定的值并不是d,
const int &r3 = d; //loss of data,r3 = 10;
为了确保让r3绑定一个整数,该句在编译器中实际上被转换成了:
1 const int temp = d; //temp是编译器创建的临时量 2 const int &r3 = temp;
所以r3最后绑定到的只是一个编译器创建的一个未命名的临时量,因而,修改d的值,并不会改变r3.
2.4.2 指针和const
指向常量的指针(pointer to const):常量只能由pointer to const 作指针,但pointer to const 仍可以指向非常量对象。(与常量引用reference to const类似)
1 double d1 = 10; 2 const double d2 = 11; 3 double *p1 = &d1; //right 4 double *p2 = &d2; // wrong 5 const double *p3 = d3;//right 6 const double *p4 = d4;//right
常量指针(const pointer):指针本身是常量,所以必须初始化,且一经初始化,值(存放在指针里面的那个地址)就不可改变。
特别的有,指向常量的常量指针:指针本身以及指针所指向的对象,一经初始化,均不可改变。
总结:
A:普通常量 B:常量指针 C:常量引用 D:指向常量的指针 E:指向常量的常量指针 F:普通指针 G:普通引用
必须初始化?----------ABCEG
值可以改变?------DFG 和 部分C:如const int& 绑定到 int 上
初始值与类型严格匹配?----AFG
2.4.3 顶层const
top-level const 表示指针本身是个常量,而底层const(low-level-const)表示指针所指的对象是一个常量。用于声明引用的都是底层cosnt。
当执行拷贝操作时,顶层const不受限制,而底层const只有当两个对象具有相同的const资格时才能执行拷入拷出操作。
2.4.4 constexpr
constexpr能够声明字面值类型(算术类型、引用和指针)。
一个constexpr的指针的初始值必须是nullptr或0或NULL或存储与某个固定地址中的对象。
函数体内定义的变量(除局部静态变量外)一般来说并非存放在固定地址中,因此constexpr指针不能指向这样的变量,但是,定义在所有函数体外的对象其地址固定不变,能用来初始化constexpr指针。
另外,constexpr对指针有效,对指针所指的对象无效。
浙公网安备 33010602011771号