前言
在Effective C++中的条款03中提到:尽可能使用const。可见const限定符对于c++程序员来说,有多么常见。今天,就来总结一下const限定符的用法。
1.作用
const限定符的作用:将一个对象转换成一个常量。
2.好处
1)便参数的修改和程序的可读性。
下面是c++ prime中提到的一个例子:
for(int index=0;index!=512;++index){//...}
这里的512是什么意思?(你程序的可读性)如果512在整个程序中出现1000次,以后要修改这个值,就要重复劳动1000次。(程序的可维护性)
如果上面这段程序改成下面这样,问题就解决了。
const int bufSize=512;
for(int index=0;index!=bufSize;++index){//...}
但是有人要问,用#define bufSize 512也能解决问题,何必要用const呢?请看下面的好处2.
2)便于定位编译错误。
如果使用#define bufSize 512,记号bufSize并没有被编译器看见。预处理器将所有bufSize替换成了512,bufSize没有进入记号表中,当此处获得一个编译错误时,可能错误信息只提到512,而不是bufSize。(参照Effective C++中的说明)
3.用法
1)常量
const TYPE ValueName=value;
TYPE const ValueName=vlaue;
第一种和第二种是完全等价的。也就是说const和类型说明符可以交换位置。
2)指针
const TYPE * VauleName=value;
TYPE const * ValueName=value;
上面这两种是等价的,都表示指针指向一个const的变量。
TYPE* const ValueName=value;
表示该指针是一个const指针。
const TYPE* const ValueName=value;
表示指针和指向的对象都是const的。
举个例子来说:
int i=0;
int a=1;
const int * j=&i;
j=&a;//ok
*j=2;//error
因为j是指向一个常量的指针,所以修改j所指向的对象的值是错误的。
int i=0;
int a=1;
int* const j=&i;
*j=2;//ok
j=&a;//error
因为j是一个const指针,不能修改j的值。
注意:可以将非const对象的地址赋给一个指向const对象的指针。但是不能将const对象的地址赋给一个普通的指针。
举个例子:
int i=0;
const int* j=&i;//ok
const int a=0;
int *b=&a;//error
3)引用
const TYPE &ValueName=value;
const 引用是指向const对象的引用。(出自c++ Prime)
举个例子:
const int i=1023;
const int &j=i;//ok
int &a=i;//error
因为i是const对象,所以不能修改i,因此也不能通过i的引用来修改i。换句话说就是:普通的引用绑定到const对象是不合法的。
注意:const引用可以初始化为不同类型的对象或者初始化为右值,比如:
int i=42;
const int &r=42;//ok
const int &r2=r+i;//ok
同样的引用对非const引用是不合法的。
4)常量成员函数
将关键字const加在 形参表之后,就可以将成员函数声明为常量。
比如:
class A
{
public:
int i;
int setA() const
{
i=1;//error
}
};
const成员不能改变其所操作的对象的数据成员。const必须同时出现在声明和定义中,若只出现在一处,就会出现编译错误。
4.注意事项
1)const对象默认为文件的局部变量。(C++Prime)
在全局作用域里定义非const变量时,它在整个程序中都能访问。如果没有特殊说明,const变量不能被其他文件访问。
如果需要被其他文件访问,将const变量指定为extern。
比如:
//file_1.cc
extern const int bufSize=512;
//file_2.cc
extern const int bufSize;
5.参考资料
1)C++Prime
2)Effective C++