C++ const限定符总结

来源:互联网 发布:linux项目部署 编辑:程序博客网 时间:2024/06/10 23:03

0.const简介

有时我们希望定义一个值不能被改变的量,以防有意无意地对其进行改动。例如我们可以定义一个缓冲区的大小bufferSize

const int bufferSize = 1024;

这样bufferSize就被定义为一个常量,任何向其赋值的行为都是非法的。
和非const对象能参与的操作相比,const类型的对象能完成其中绝大部分。唯一的区别就在于const类型对象的值不能被改变。

1.const初始化

由于const对象的值不能被修改,所以对其初始化就必不可少。

举例:
const int a = 1024;//正确,编译时初始化const int b = get_size();//正确,运行时初始化const int c;//错误,未经初始化的常量/*注意,一个当用一个常量去初始化另一个变量时,与其是否为常量并无关系*/const int d = a;//正确, a的值被拷贝给了dint e = d;//正确,d的值被拷贝给了e

2.const与引用

2.1定义

像绑定到其他对象上一样,也可以把引用绑定到const对象上,我们称之为 对常量的引用(reference to const),或称为常量引用、常引用
特点:对常量的引用不能用作修改它所绑定的对象。
定义引用时,在前面加上const限定符,即可定义一个对常量的引用。

举例:
int n = 1024;int & r = n;const int & const_r = n;//r为对n的常引用/*可将const_r理解为const int & 类型的量,区别于普通引用r为const int 类型的量*/r = 2048;//正确,普通引用可以修改所绑定对象const_r = 2048;//错误,常引用不能修改所绑定对象

2.2 const T & 和 T &

const T & 和 T & 是不同的类型,
  • T &类型的引用或T类型的变量可以用来初始化 const T &类型的引用(换言之,常量引用没有规定其所绑定的对象是否为常量);
  • const T 类型的常变量和const T &类型的引用则不能用来初始化 T &类型的引用(除非进行强制类型转化)。
            
举例:
int n = 1024;int & r1 = n;//r1绑定对象n,可修改nconst int & const_r = r1;//const_r也绑定对象n,但是不可修改nint & r2 = const_r;//错误,r2是一个普通的非常量引用

关于C++引用的特例

C++规定引用的类型必须与其所引用的对象类型一致,但有种例外情况:初始化常量引用时允许用任意表达式作为初始值,只要该表达式的结果能转换成引用的类型即可。

所以允许一个常量引用绑定非常量的对象、字面值,甚至是一个一般表达式。

3.const与指针

3.1指向常量的指针(pointer to const)

类似于常量引用,指向常量的指针(pointer to const)不能用于改变其所指的对象。定义方法为将const放在 * 前面。
举例:
const double pi = 3.14;//pi是个常量,其值不能被改变double *ptr = π//错误,ptr是一个普通指针const double *cptr = π//正确,cptr是一个指向常量的指针(另一种写法double const * cptr,无区别,保证const在 * 前面即可)*cptr = 1.23;//错误,指向常量的指针不能改变其指向的对象

要想存放常量对象的地址,只能使用指向常量的指针。和常量引用一样(参考2.2),指向常量的指针并没规定其所指向的对象必须是一个常量。
C++规定的仅仅是:不能通过指向常量的指针去改变所指对象的值而已,而没有规定那个对象的值能否通过其他途径改变。
const int a = 1024;int b = 2048;const int *cptr_a = &a;//正确const int *cptr_b = &b;//正确

小结:所谓指向常量的指针、指向常量的引用,不过对是那个指针或引用规定不准改变所指向的对象而已,与对象是否为常量没有关系。


关于C++指针的特例
C++规定指针的类型必须与其所指向的对象的类型一致,但有一种例外是允许另一个指向常量的指针指向一个非常量对象。(与上节关于引用的特例类似)

3.2常量指针(const pointer)

指针是一种对象,而引用不是。因此允许像其他对象类型一样,将指针本身定义为一个常量,即常量指针(const pointer)。
常量指针的定义方法为将 * 放在const关键字后面,这样的写法意味着:不变的是指针本身而非指针所指的那个对象。
与其他常量一样,常量指针必须初始化,且一旦初始化完成,它的值(即存放其中的地址)就不能被改变了。
举例:
int a = 1024;int * const p1 = &a;//p是一个常量指针,将一直指向aint const * p2 = &a;//p是一个指向常量的指针double pi = 3.14;const double * const p = π//p是一个 指向常量对象 的 常量指针
技巧:弄清这些声明的一个有效方法是从右往左读。
上例中,离p1最近的符号是const,意味着p1本身是一个常量对象,对象类型由声明其他部分确定。声明中下一个符号是 * ,意思是p1是一个常量指针。最后由声明符int得出p1是一个指向int对象的常量指针。同理,可推测出p是一个常量指针,他指向的对象是一个double类型的常量

注意:
常量指针本身是一个常量,并不意味着不能通过指针修改其所指对象的值,能否修改完全取决于所指对象是否为常量,与常量指针无关。
例如上例中p1指向的是一个一般的非常量a,完全可以用p1来修改a的值。

3.3顶层const与底层const(top-level const, low-level const)

如前文所述,指针本身是一个对象,而它又可以指向另一个对象。因此,指针本身能不能改变(指针本身是否为常量)和指针所指的对象能不能被改变是两个完全独立的问题。
顶层const(top-level const)表示指针本身是一个常量,而用底层const(low-level const)表示指针所指的对象是一个常量。

更一般的,顶层const可以表示任何对象是常量,例如const int p1 = 1024; p就是一个顶层const,不能改变p的值。而底层const则与指针和引用等复合类型的基本类型部分有关。
指针既可以是顶层const,也可以是底层const。例如const int * const p2 = p1;  * 号前面const声明p2为底层const,而 * 号后面const声明p2为底层const。

当执行拷贝操作时,常量是顶层const还是底层const区别明显。其中,顶层const不受影响。而底层const的限制不容忽视。执行对象的拷贝操作时,拷入和拷出的对象必须具有相同的底层const资格。 


参考资料:《C++ Primer 5th》
原创粉丝点击