在刚接触const时,只是简单的记const修饰的变量为常量,然而,const远非如此。
一、初级部分
1 .const作为限定符
(1)修饰一般变量,定义const对象
const int a = 10;
a = 15; //error
const int b;//error
b = a;
const限定了它修饰的变量a只能读,而不能被修改,这在编译时进行检测。变量a本质上依然是变量,或者说仍然是一个左值,具备一个左值应有的属性。
而const修饰变量b时,规定在定义时需要进行初始化,否则报错。
在http://www.embedu.org/Column/Column311.htm一文中,有如下代码:
int main()
{
int buf[4];
const int a = 0;
buf[4] = 97;
printf("%d",a);
return 0;
}
只是我在VS2008中得到的依然是0!
(2)const对象在文件中默认为局部变量
先看如下代码:
//--------file_1.cpp
const int bufsize = 1234;
//--------file_2.cpp
extern const int bufsize;
int main()
{
printf("%d",bufsize);
return 0;
}
上述代码编译通不过,那是因为在全局作用域中声明的变量bufsize在定义它的文件中是局部变量,不能被其他文件访问。
注:在全局作用域定义非const变量时,默认为extern。而要使const对象能够被其他文件访问,则必须显式指定为extern。
2.const与define
在《Effective C++》条款2:尽量以const,enum,inline替换#define。
为什么呢?
怎么说呢,#define是一种预处理,在编译之前做一个字符的替换,它缺乏一种类型检查,所以可能会带来意想不到的隐患。相关知识可以看#define介绍。编程过程中,尽量使用const代替#define。
进一步了解可以百度或者google:折叠常量
3.const与&、*
const引用就是指向const对象的引用。引用一旦定义,就不能再指向其他对象,所以必须初始化。非const引用只能初始为非const同类型对象,而const引用它可以初始化为不同类型的对象或者右值。例如:
int i = 20;
double dval = 1.34;
const int &r = 20;//ok
const int &r2 = i;//ok
const int &r3 = i+20;//ok
const int &r4 = dval; //ok
对于const int &r4 = dval;
编译器会将以上代码转化成如下形式编码:
int temp = dval;
const int &r4 = temp;
接下来我们看const限定符和*,依照惯例,先看代码:
const int *pContents;//①
int * const pContents;//②
const int * const pContents;//③
对于上述三种情况,假如你能说清楚,恭喜你,你已经不用担心const指针问题了。在《effective C++》中有一种简单的判别方法:如果const在星号左边,则表示指针指向的是一个const对象,你不能修改它所指向的值,但是你能够修改指针本身;如果const在星号右边,则表示指针本身是const,你可以修改指针指向的对象,但是指针是只读的。而③则表示,你既不能修改指针,也不能修改指针所指向的对象。上面提到,对于一个const对象,它的引用应该是具备const特性的,同样,指向一个const对象的指针也应该具备const特性。如果指针是非const的,而试图去指向一个const对象时,就会报错。但是const指针可以接受一个非const对象的地址,不过依然不能通过指针去修改它指向的值,但是可以用其他方法修改它指向的值。
const double pi = 3.14;
double *ptr = π//error
double *cptr = π//ok
double dval = 2.34;
const double *cptr = &dval;//ok
*cptr = 3.45;//error
//通过非const指针修改非const对象
double *ptr = &dval;
*ptr = 3.45;//ok
在《C++primer》里说:如果把指向const的指针理解为“自以为指向const的指针”,这可能会对理解有所帮助。确实如此!!!
二、中级部分
1 const与函数