复合类型--引用与指针

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对指针有效,对指针所指的对象无效。

 

posted on 2015-09-02 20:57  Perry333  阅读(285)  评论(0)    收藏  举报

导航