在上一节中说到了基本的指针的定义与解析,下面便是升级版,多级指针的理解:
所谓多级指针在于有多重的指针导向,因为指针是一个对象,在内存中会分配空间,所以可以定义一个指针来指向该指针变量,也就是指向指针类型的指针。那么在解析的时候也就需要进行多重解析了,第一重解析即得到一级指针的地址,第二重解析即得到一级指针所指向的内容。如下图所示:
另外,正如给一般的变量去别名一样,既然指针也是一种变量,那么也就可以给它取一个别名啦~~只是这个时候一个变量前面就有多个修饰符了,为了方便理解,最简便的方法是从右至左来解读符号,(*&)——改变量是一个引用型,并且是一个指针类型的引用,如下图所示:
之前在项目编程中,也经常使用到const限定符来对变量进行限定,经常是在函数参数定义时使用以使得传递到函数的参数在该函数处理中原始性不会被破坏。若定义一个const修饰的变量时需要对其进行初始化,该初始化的值可以是其他的已有初始化的变量,或者其他有实际值的值或表达式,之后该值便不能再被修改。
好了,知道了const的基本用法,下面来说说当有多个文件中共享或者单独定义const变量的方法:
常规地,在每个文件中定义的重名的常量型变量其作用域也只在其所在的文件,但若希望某一个文件中定义的变量在其他文件中也能共享,此时只需在定义时在其前面加上限定词extern关键词,然后在其他文件中声明时也添加上extern即可,此时该文件中的变量可以不用赋初值,用了extern做修饰则说明它的定义在别处。如下图:
接下来就来说说常量变量的引用问题,顾名思义,这种引用是给一个常量型的变量取一个别名,但在给其赋值时,常量型的引用类型只能是常量型(const int i=0;const int &r=i ),但是,常量型引用的初始化值可以是非常量型的任意表达式(int i=0;const int &r=i),只要最终该表达式可以转换成一个确定的值即可。如下图所示:
在这儿说明一下,为什么非const型的引用无法实现const型变量对其赋值。这就要说到引用存在的意义了,引用即别名,也就是通过对该别名值的改变同等于对其绑定值的改变,但是,如果其绑定值为const类型,也就是其值本身就不可变,那么这种非const型的引用也就失去了意义,所以不存在将const型的变量赋值给非const型的引用。
总之,简单来讲,就是等号的左边有const的情况下,右边可以随意;但是当等号的右边是const型时,则等号左边只能是const 型的引用
上面分别说明了指针与const限定符,那么下面来说说两者的结合体吧~~也就是指向常量的指针。
指向常量的指针(const int*r=&p)即该指针所指向的为常量型的变量,但也并非非得是常量不可,也可以是非const型,也就是等号左边有const,但对于等号右边是否为const型并不在意,其强调的是,不能通过该指针对其所指的对象进行值的改变,而对所指对象并无特别的要求。如下图所示:
说完了指针指向const型的变量后,下面来说说const指针,因为指针和引用最大的不同在于指针是对象占用内存空间,而引用不是对象,在内存中是没有单独地址的,所以可以将指针定义成const常量型。与一般的常量型变量一样,在定义时需要赋初值,而且一旦该指针变量所存的地址值确定后则不能再被改变(int i=0;int *const p=&i),如下图所示:
需要注意的是:
也就是const型指针所存的地址值不能被改变,但其所指对象的值是否能被改变则取决于该变量是否为const型。在这儿就牵涉到了顶层const与底层const的概念,所谓顶层与底层,指的是const所在的层次级别,顶层即常见的常量型直接定义变量,底层是针对常量型引用以及指向const类型的指针而言的。如下图所示:
好了,对于const限定符其绕来绕去也就是三种简单情况的组合,
1:变量直接定义成const常量型,并初始化(const int i=1)
2、const与引用的组合:const int &a=i;
3、const与指针的组合:const int *p=&p int *const p=&p
以上三种即为最基本的const限定符的使用,这些const均为顶层const,其他的更复杂的组合方式即为这三种基本方式的结合,如: const int*&b=p(p也可以不是const类型的),const int * const c=p(p也可以不是const类型的)
那么针对更复杂的组合 ,记住从右往左读各个限定符一层层的理解即可~
下面再来了解一下常量表达式(constexpr):
在这儿值得注意的是,在对指针的修饰中,constexpr不能简单地用const替换,因为constexpr只用来限定指针是常量而对其所指的内容不作限定,如下图: