引用(左值引用):
引用就是给对象取了另一个名字,声明符&d的形式来定义引用类型。
一般在初始化变量时,初始值会被拷贝到新建的对象中。然而定义引用时,程序把引用和它的初始值绑定(bind)在一起,而不是将初始值拷贝给引用。一旦初始化完成,引用将和它的初始值对象一直绑定在一起。因为无法令引用重新绑定到另外一个对象,因此引用必须初始化。
引用并非对象,相反的,它只是为一个已经存在的对象所起的另外一个名字。因为引用本身不是一个对象,所以不能定义引用的引用。
指针:
指针( pointer)是“指向( point to)”另外一种类型的复合类型。与引用类似,指针也实现了对其他对象的间接访问。然而指针与引用相比又有很多不同点。其一,指针本身就是一个对象,允许对指针赋值和拷贝,而且在指针的生命周期内它可以先后指向几个不同的对象。其二,指针无须在定义时赋初值。和其他内置类型一样,在块作用域内定义的指针如果没有被初始化,也将拥有一个不确定的值。
指针存放某个对象的地址,要想获取该地址,需要使用取地址符(操作符&),如果指针指向了一个对象,则允许使用解引用符(操作符*)来访问该对象。
指针的值(即地址)应属下列4种状态之一:
1.指向一个对象。
2.指向紧邻对象所占空间的下一个位置。
3.空指针,意味着指针没有指向任何对象。
4.无效指针,也就是上述情况之外的其他值。
空指针(null pointer)
不指向任何对象,在试图使用一个指针之前代码可以首先检查它是否为空。得到空指针最直接的办法就是用字面值nullptr来初始化指针,这也是C++11标准的内容。
赋值与指针:
指针和引用都能提供对其他对象的间接访问,然而在具体实现细节上二者有很大不同,其中最重要的一点就是引用本身并非一个对象。一旦定义了引用,就无法令其再绑定到另外的对象,之后每次使用这个引用都是访问它最初绑定的那个对象指针和它存放的地址之间就没有这种限制了。和其他任何变量(只要不是引用)一样,给指针赋值就是令它存放一个新的地址,从而指向一个新的对象。
void*
void*是一种特殊的指针类型,可用于存放任意对象的地址。一个void*指针存放着一个地址,这一点和其他指针类似。不同的是,我们对该地址中到底是个什么类型的对象并不了解:
指向指针的指针:
通过*的个数可以区分指针的级别。也就是说,**表示指向指针的指针,***表示指向指针的指针的指针,以此类推:
此处,pi存储整形ival的地址,ppi存储pi的地址。
指向指针的引用:
引用本身不是一个对象,因此不能定义指向引用的指针。但指针是对象,所以存在对指针的引用。
空悬指针:
new申请的动态内存对象是无名对象,所以要用指针指向动态内存,而动态内存要用delete释放,delete后面只能跟指针,delete释放后,指针就变成了人们所说的空悬指针(dangling pointer),即,指向一块曾经保存数据对象但现在已经无效的内存的指针。所以delete之后再赋值nullptr,指针就清楚的不指向任何对象。
指向常量的指针和引用:
指针和引用的类型必须和所指的类型保持一致,但是有例外,一种情况是,指向常量的指针和指向常量的引用指向了一个变量,这是允许的,但是依然不能通过这个指针或者引用去修改这个变量,因为指针或者引用以为自己指向的是常量。
指针是对象,引用不是,所以允许把指针定义为常量,常量指针必须初始化,把*放在const前面说明指针是一个常量,即不变的是指针本身的值而不是指向的那个值,如果指向的是变量,依然可以通过指针修改所指的变量的值。
顶层const,底层const
顶层const就是指针本身是个常量,底层const就是指针所指的对象是一个常量。声明引用的都是底层const。执行对象的拷贝时,注意底层的const,因为底层的const设计到常量和变量之间不能赋值。
指针常量——指针类型的常量(int *const p)顶层const
常量指针——指向“常量”的指针(const int *p, int const *p)底层const