我们来看一段for循环语句.
for(int index=0;index=512;++index)
{
//....
}
两个问题.第一个: 程序的可读性.作为旁人来看,他可能会问,比较index与512有什么意思呢?循环在做什么呢?512的作用目的又是什么呢?(本例中,512被称为魔数(magic number),它的意义在上下文中没有体现出来.好像这个数是魔术般从空中出现的)
第二个问题:程序的可维护性.考虑到以后修改维护,如果这个程序非常庞大,512出现了100次,进一步假设在这100次中,有80次是表示某一特殊缓冲区的大小,剩余20次用于其他目的.现在我们需要把缓冲区的大小增大到1024.要实现这一改变,必须检查每个512出现的位置.我们必须确定(在每种情况下都准确的确定)哪些512表示缓冲区大小.而哪些不是.改错一个都会使程序崩溃,又得回过头来重新检查.
解决问题的办法是使用一个初始化为512的对象:
int bufSize=512; //input buffer size
for(int index=0;index!=bufSize;++index)
{
//...
}
通常使用好记的名字切合实际用途的名字,例如bufSize,增加了程序的可读性.现在是对对象bufSize测试而不是对字面值常量512测试:
index!=bufSize
现在如果想要改变缓冲区大小,就不再需要查找和改正80次出现的地方.而只有初始化bufSize那行需要修改,这种方法不仅明显减少了工作量,而且还大大减少了出错的可能性.
来看看如何定义const对象
定义一个变量代表某一常数的方法依然有一个严重的问题.就是bufSize是可以被修改的,不管是有意还是无意,这就是不稳定不确定性因素.const限定符提供了一个解决方法,它把一个对象转换成一个常量.
const int bufSize=512; //input buffer size
定义bufSize为常量并初始化为512.变量bufSize仍然是一个左值,只不过它不能被修改,任何修改bufSize的尝试都会导致编译错误:
bufSize=0; //error:attempt to write to const object
因为常量在定义后就不能被修改,所以定义时必须初始化:
const std::string hi="hello!"; //ok:initialized
const int i,j=0; //error:i is uninitialized const
const对象默认为文件的局部变量
在全局作用域里定义非const变量时,它在整个程序中都可以访问.我们可以把一个非const变量定义在一个文件中,假设已经做了合适的声明,就可以在另外的文件中使用这个变量.
//file_1.cc
//defines and initializes a const that is accessible to other files
extern const int bufSize=fcn();
//file_2.cc
extern const int bufSize; //uses bufSize from file_1
//uses bufSize defined in file_1
for(int index=0;index!=bufSize;++index)
//......
file_1.cc通过函数fcn()的返回值来定义和初始化bufSize.而bufSize定义为extern,也就意味着bufSize可以在其他的文件中使用.file_2.cc中bufSize的声明同样是extern;在这种情况下,extern标志着bufSize是一个声明,没有初始化式.
非const变量默认为extern,要使const变量能够在其他的文件中访问,必须显式地指定它为extern
习题: for(int i=0;i<100;++i) 合法,但风格很糟糕,有什么问题呢?如何改善?
用const定义一个对象来代替100,见上文,不重复了.
看看下面语句哪些合法,哪些不合法,解释
(a)const int buf;
(b)int cnt=0;
const int sz=cnt;
(c)cnt++;sz++;
(a),没有初始化,定义const变量的时候必须初始化
(b)合法.通过cnt来定义const变量.
(c)不合法,修改了const变量sz.