const修饰符杂谈

时间:2021-09-19 21:06:45
         顾名思义,const就是constant的缩写,在编程语言中表示其所修饰的程序语言的元素是不可以改变的。它可以修饰的程序语言的元素有数据类型(内建的和用户自定义的)、函数、函数返回值、函数参数和类,而用const修饰的数据类型一般被称为常量。

相同数据类型的常量和非常量间是不可以随意的进行相互转换的: 常量可以向下兼容非常量,但是常量不能直接转换为非常量。这个问题主要是出现在调用函数时的参数传递和指针的地址获取上。由上面说的转换规则可知,声明、定义函数时,最好使用const来修饰函数的参数,这样一来可以增大函数的适用范围。而指针常量则是一个比较特别的存在,有三种常量类型:指向地址不可变、指向内容不可变、二者皆不可变,形式如下:

const int *pi//指向内容不变

int *const pi//指向地址不变

const int *const pi//二者皆不变

int const *const pi//二者皆不变

同样,由转换规则可知,我们可以用一个常量指针指向一个非常量的地址,但是不可以用一个非常量指针指向一个常量的地址。

C语言中,const的含义较为简单,它表示所修饰的普通变量在进行初始化后就不可以被修改。C语言中允许对const性质的变量先声明,而后定义,而且常量链接进行的是外部链接,这与C++中大有不同。

而在C++中,const被赋予了更多的意义:

首先,C++中的const常量是不允许单独声明的,除非使用extern修饰或是在类中。也就是说大多数情况下,C++中的const只有定义;

其次,C++中的常量链接时进行的是内部链接,只是文件内部可见的。这个特性在进行大型工程编写时要特别注意;

再次,C++中的const拥有const fold的特性,这也是C++中针对const引入的最重要的特性。const fold就是将常量写入编译器的符号表,而不给常量分配内存,在编译时展开常量即可。我们知道,在CC++中数组长度是在编译时确定的,而一般的变量则是在编译之后分配内存并赋值的,这也是为什么CC++中不能用变量定义数组长度的原因。C语言中的常量和普通变量是一样的,只是赋值之后就不可改变罢了。所以C语言中同样不能使用常量定义数组的长度,而只能通过诸如:

#define array_length 100

之类的宏定义来定义数组的长度以便于代码阅读、数组长度修改和管理。但是宏定义有个致命的缺陷——不能进行类型检查,这将会导致一些难以发觉的错误。而C++由于引入了const fold这一特性,多数情况下常量值是在编译时可见,也就是说,C++中的常量可以用来定义数组的长度,起到了替代宏定义的作用,增强了代码的安全性和可控性。值得注意的是const fold这一特性是一个编译器尽可能实现的性质,而不是一个必须实现的性质。若是程序需要获得某个常量的地址,比如说进行地址或引用的传递,那么编译器就会为常量分配地址,但这并不就说明该常量在编译时就不可见,不能定义数组长度。只有那些只有在程序运行时才能获值的常量才在编译时不可见,比如说:

       const int i = scanf(“%d”,&i);

C++中比较特别的常量是类的成员常量和被const修饰的成员函数。成员常量的特性反倒比较贴近于C语言中对常量的定义。就是说,类中的常量和普通变量一样,只是初始化后不能改变罢了,在编译时不可见,不能用来定义数组的长度。如果非要想使用类中的常量来定义数组长度,则需再加上static修饰常量。特别要注意的是,类中的常量除了用static修饰的以外不能直接赋初值,能且只能在构造函数的初始化列表中初始化,之后则不可改变。而被const修饰的成员函数则意味着不能改变除了用mutable修饰的成员变量以外的任何成员变量。