const是C++语言引入的一个关键字,是“不变的”、“常量”的意思。用const定义一个变量,实际上是定义了一个“常变量”(即只读变量)。但是,const的用法远不是这么简单,因为C++中有指针、引用、函数等多种机制,所以和const组合在一起,就会遇到很多实际问题。下面从4个方面总结一下const的用法。
(1)const的位置
const的位置比较灵活。一般说来,除了修饰一个类的成员函数外,const不会出现在一条语句的最后。以下是一个使用const的例子。
1. #include <iostream>
2.
3. int main()
4. {
5. int i = 5;
6. const int v1 = 1;
7. int const v2 = 2;
8. const int *p1;
9. int const *p2;
10. //以下三条语句都会报编译错误,为什么?
11. //const *int p3;
12. //int *const p3 = &v1;
13. //int *const p3;
14. int *const p3 = &i;
15. const int *const p4 = &v1;
16. int const *const p5 = &v2;
17. const int &r1 = v1;
18. int const &r2 = v2;
19. //以下语句会报编译错误,为什么?
20. //const &int r3;
21. //以下语句会报警告,并忽略const
22. int &const r4 = i;
23. std::cout<<*p4<<std::endl;
24. return 0;
25. }
复制代码
程序的输出结果是:1。当然,各位也可以自行考察一下其他变量的值。以上程序演示的是const的位置与它的语义之间的关系。表面上看起来很复杂,但实际上是有规律可循的。也就是说,const和数据类型结合在一起,形成所谓”常类型“,然后利用常类型来声明或定义变量,这样就产生了常变量。const用来修饰类型时,既可以放在类型的前面,也可以放在类型的后面;用常类型声明或定义变量时,const只会出现在变量前面。const和被修饰类型之间不能有其他标识符存在。
在理解有const存在的声明语句时,关键是要搞清楚到底什么是“不可变”的。对一个具体的变量来说,如果const直接出现在该变量的前面,则该变量的值一旦初始化就不能再改变。所以,const int v1;和int const v1;都是合法的,而且是等价的。由于const直接出现在v1前,所以v1是只读变量(常变量)。而int const *p和int *const p则是不同的声明语句,原因是前者的const修饰的是int,而后者的const修饰的是int*。前者是常指针,表示指针p指向的是一个只读的整型量(指针所指单元的内容不允许修改),而指针本身可以指向其他的常变量;而后者是指针常量,表示指针p本身的值不能修改(const直接出现在p的前面),即一旦指针p指向某个整数之后,就不能再指向其他整型量。如果指针被定义为指针常量,那么在定义它的时候必须同时初始化,否则编译器报错。
引用本身可以理解成一个指针常量,所以在引用前使用关键字const没有意义。上例中int &const r4 = i;语句的const是多余的,编译器在给出警告信息后,自动忽略const的存在。常引用是指将被引用对象当做一个常量,也就是不允许通过引用来修改被引用对象的值。常引用有它独特的特点,具体可参阅关于常引用的资料。要清楚的一点是:普通变量可以当做常变量来看待,但反过来不可以。
在很多情况下,为了表达同一种语义,可以将const放在不同的位置,如前面的例子。但在某些情况下,const只能放在特定的位置,否则意义就会完全不一样。下面是一个const配合二重指针的例子。在这个程序中,const的位置是不能随意变动的。
1. #include <iostream>
2.
3. int main()
4. {
5. int const **p1;
6. int *const *p2;
7. int i = 5;
8. int j = 6;
9. const int *ptr1 = &i;
10. int *const ptr2 = &j;
11. p1 = &ptr1;
12. p2 = &ptr2;
13. std::cout<<**p1<<std::endl;
14. std::cout<<**p2<<std::endl;
15. return 0;
16. }
复制代码
程序的运行结果是:
5
6
在程序中定义了两个二重指针p1和p2,它们的声明分别是int const **p1和int *const *p2,但含义完全不同。p1不是指针常量,它所指向的变量类型是int const*(指向整型常量的指针);p2也不是指针常量,但它所指向的变量是指针常量(int* const,即指向整型的指针常量)。所以为p1和p2赋值是有讲究的。如果在上面的程序中,使用这样的赋值p1 = &ptr2或p2 = &ptr1,都会产生编译错误。各位有兴趣的可以自行试验一下,并分析产生错误的原因。