c/c++ const关键字

C/C++ const关键字

  在C语言和C++中经常要用到const关键字,最简单的用法是使用它定义常量,如果一个变量被const修饰,那么它的值就不能再被改变。这是const关键字最根本的功能。既然用它定义的变量不可变,那么他与#define有什么区别呢?

  1. const关键字定义的变量在堆栈中分配了空间,const修饰的常量是一个Run-Time的概念,变量在程序中确确实实的存在,可以被调用、传递。
  2. #define只是在编译时只是对值简单的替换,不能进行类型检查,它是Compile-Time概念,他的生命周期止于编译器。
  3. const可以保护被修饰的东西,防止恶意篡改。
  4. 具体不同的编译器存在一些差别。

一、修饰局部变量

const int n = 5;
int const n = 5;

 上述两种写法完全一致,表示变量n定义完成后,不能再被修改,需要注意的是在使用const修饰变量时,一定要对变量进行初始化,否则之后就不能对其进行赋值了。
 在全局作用域里定义非const变量时,它在整个程序中都可以访问。如下所示:

//file_1.c
int counter; //definition

//file_2.c
extern int counter; //uses counter from file_1
counter++; //increments counter defined in file_1

 与其他变量不同,除非特别说明,在全局作用域声明的const变量是定义该对象的文件的局部变量。此变量只存在于那个文件当中,不能被其他文件访问。
 通过指定const变量为extern,就可以在整个程序中访问const对象。如下所示:

//file_1.c
//defines and initializes a const that is accessible to other files
extern const int bufSize = fcn();

file_2.c
extern const int bufSize;//uses bufSize from file_1

 由此可知,非const变量默认为extern。要使const变量能够在其他文件中访问,必须显式地指定它为extern。

二、const引用

const引用是指向const对象的引用:

const int ival = 1024;
const int &refVal = ival;//ok,both reference and object are const
int &ref2 = ival; //error,nonconst reference to a const object

 可以读取refVal但不能修改,因此,任何对refVal的修改都是不合法的。使用ival初始化ref2是不合法的,因为ref2是普通的非const引用。
 严格来说,“const引用”的意思是“指向const对象的引用”。“非const引用”表示指向非const类型的引用。
 const引用可以初始化为不同类型的对象或者初始化为右值,如字面值常量:

int i = 42;
const int &r = 42;
const int &r2 = r + i;

 同样的初始化对于非const引用却是不合法的,而且会导致编译时错误。

 观察将引用绑定到不同的类型时所发生的事情,最容易理解上述行为。加入我们编写:

double dval = 3.14;
const int &ri = dval;

编译器会把这些代码转化成如下:

int temp = dval;
const int &ri = temp;

 如果ri不是const,那么可以给ri赋一个新值。这样做不会修改dval,而是修改了temp。期望对ri的赋值会修改dval的程序员会发现dval并没有被修改。所以仅允许const引用绑定到需要临时使用的值完全避免了这个问题,因为const引用是只读的。

注解:

  1. 非const引用只能绑定到与该引用同类型的对象。
  2. const引用则可以绑定到不同但相关的类型的对象或绑定到右值。

三、指针和const限定符

指向const对象的指针

 指针可以用来修改其所指对象的值。但如果指针指向const对象,则不允许用指针来改变其所指向的const值。为了保证这个特性,c++语言强制要求指向const对象的指针也必须具有const特性:

const double *cptr; //cptr may point to a double that is const

 这里的cptr是一个指向double类型const对象的指针,const限定了cptr指针所指向的对象类型,而非cptr本身
也就是说,cptr本身并不是const,在定义时不需要对他进行初始化,如果需要的话,允许给cptr从新赋值,使其指向另一个const对象。但不能通过cptr修改其所指向对象的值。
 把一个const对象的地址赋给一个普通的、非const对象的指针也会导致编译时的错误。

const double pi = 3.14;
double *ptr = π //error: ptr is a plain pointer
const double *cptr = π //ok:cptr is a pointer to const

 不能使用void *指针保存const对象的地址,而必须使用const void *类型的指针保存const对象的地址:

const int universe = 42;
const void *cpv = &universe; //ok
void *pv = &universe; //error

 允许把非const对象的地址赋给指向const对象的指针,例如:

double dval = 3.14;
const double cptr = &dval;

尽管dval不是const对象,但任何企图通过指针cptr修改其值的性唯都会导致编译时的错误。cptr一经定义,就不允许修改其所指对象的值。在实际的程序中,指向const的指针常用作函数的形参。将形参定义为指向const的指针,以此确保传递给函数的实际对象在函数中不因为形参而被修改。

const指针

除了指向const对象的的指针外,c++语言还提供了const指针—本身的值不能被修改。

int errNumb = 0;
int *const curErr = &errNumb; //curErr is a constant pointer

const指针的值不能修改,这就意味着不能使curErr指向其他对象。

指向const对象的const指针

知道了上面的两个概念,那么我们还可以如下定义指向const对象的const指针。

const double pi = 3.14159;
const double *const pi_ptr = π

本例中,既不能修改pi_ptr所指向对象的值,也不允许修改该指针的指向。

参考资料

《C++ Primer》


   转载规则


《c/c++ const关键字》 anhua 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
C/C++ extern关键字 C/C++ extern关键字
C/C++ extern关键字本篇文章主要围绕一下几个问题对extern关键字进行说明。 声明和定义 变量和函数的声明 extern和static extern关键字与头文件的联系 extern “C” extern和const 声明和
2019-12-16
下一篇 
GitHub高级检索 GitHub高级检索
使用GitHub的高级检索功能更加高效、准确、快速的找到自己所感兴趣或需要的开源项目
2019-12-06
  目录