const限定符用于限定变量或对象的值。const对象一旦创建其值不能再改变。在C++中,const与引用和指针相结合,有多种用法。下面将结合<C++ Primer>第五版的内容做一个较详细的介绍。
1.const对象初始化
const对象必须初始化,初始化可以是任意复杂的表达式,如:
const int i=get_size();
const int j=42;
2.如何在文件间共享const对象
当以编译时初始化的方式定义一个const对象时,编译器将在编译过程中把用到该变量的地方都替换成对应的值。替换的前提是编译器知道变量的初始值。为了避免对同一变量的重复定义,默认情况下,const对象被设定为仅在文件内有效。值得注意的是,当多个文件中出现了同名的const变量时,其实等同于在不同文件中分别定义了独立的变量。
文件间共享const变量,即希望编译器不会为每个文件分别生成独立的变量。解决的办法是,对于const变量不管是声明还是定义都添加extern关键词,这样只需定义一次就可以,如:
// file_1.cc中定义并初始化了一个常量,该常量能被其他文件访问
extern const int bufSize=fcn();
// file_1.h头文件中对bufSize进行声明
extern const int bufSize;
3.const的引用
对const的引用通常也被简称为“常量引用”(reference to const)。不同于普通引用,对常量的引用自身也是const类型。如:
const int ci=1024;
const int &r1=ci; //注意这里的引用是常量,去掉const错误
常量引用仅对引用可参与的操作作出限定,对于引用的对象本身是不是一个常量未做先限定。如:
int i=42;
int &r1=i; //引用r1绑定对象i
const int &r2=i; //r2也绑定对象i,但是作为常量引用,不允许通过r2修改i的值
4.指针和const
4.1指向常量的指针
与引用类似,想要存放常量对象的地址,只能使用指向常量的指针(pointer to const)。如:
const double pi=3.14;
const double *cptr=π
和常量引用一样,指向常量的指针也没有规定其所指的对象必须是一个常量,即对const的引用和指针都必须是const类型的,但const类型的指针和引用也可以针对非常量的对象。如:
double dval=3.14; //dval是一个双精度浮点数,非常量
cptr=&dval; //指向常量的指针cptr也可以指向dval
4.2常量指针
指针本身也是对象,可以把指针本身定义为常量,称为常量指针(const pointer)。常量指针必须初始化,一旦初始化后其值(存放在指针中的地址)不再变化。把*放在const关键词之前用以说明指针是一个常量。如:
int errNumb=0;
int *const curErr=&errNumb; //curErr为常量指针,将一直指向非常量errNumb, 可以通过curErr修改errNumb的值.
const double pi=3.14159;
const double *const pip=π //pip是一个指向常量对象的常量指针
对于较复杂的定义,可采取从右向左阅读的有效方法。如pip,离pip最近的是const说明pip为常量,加上*说明pip为常量指针,double说明pip指向double类型对象,const说明pip指向的是常量。
4.3顶层const和底层const
狭义的讲,顶层const(top-level const)表示指针本身是个常量,相对的底层const(low-level const)表示指针所指的对象是一个常量。
广义来讲,顶层const可以表示任意的对象是常量,且对任何数据类型都适用。底层const则与指针和引用等复合类型的基本类型部分有关。比较特殊的是,指针类型既可以是顶层const,也可以是底层const。来看几个例子:
int i=0;
int *const p1=&i; //p1为常量指针,本身是一个常量,为顶层const
const int ci=42; //ci为常量,是顶层const
const *p2=&ci; //p2为指向常量的指针,其本身的值可以变,为底层const
const int *const p3=p2; //靠右的为顶层const,靠左的是底层const,p3既是顶层const也是底层const
const int &r=ci; //引用本身不是对象,用于申明引用的const都是底层const
在执行拷贝操作时,常量是底层const还是顶层const区别明显,我想这也是将二者进行明显区分的意义所在。顶层const不受拷贝影响:
i =ci; //拷贝ci的值,ci是一个顶层const,对此操作无影响
p2=p3; //p2和p3指向的对象类型相同,p3顶层const的部分不影响
另一方面,底层const受拷贝限制明显。当执行对象的拷贝操作时,考拷入和拷出的对象必须具有相同的底层const资格,或者两个对象的数据类型必须能够转换。一般来说,非常量可以转化为常量。
p2=p3; //两者都具有底层const的属性
p2=&i; //i为普通int变量,int*能转换为const int*
const int &r2=i; //引用为底层const,可以绑定到普通int上
5.总结
const作为单纯的常量本身并不复杂,但是与引用和指针相结合以后则较为复杂,需要厘清其中的关系,才能做到灵活应用。
参考文献
Stanley B.Lippman,Josee Lajoie,Barbara E.Moo.C++ Primer(5th edition)