C++ const 允许指定一个语义约束,编译器会强制实施这个约束,允许程序员告诉编译器某值是保持不变的。如果在编程中确实有某个值保持不变,就应该明确使用const,可以减少奇怪的BUG。
1. 修饰普通成员变量
对于指针和引用类型,const一般分为顶层const和底层const。顶层const就是表示自己本身是常量,不能改变。底层const就是表示自己所引用的或指向的是常量,不能改变自己指向或引用的对象的值。
从上面就可以知道,对于一般类型(非指针或引用), 如int, const指的就是顶层引用了,表示自己是常量,因为他们不能指向或引用别人。
对于一般的const用法在此就不再阐述,这里以const 修饰指针为例,修饰引用与此大致相同。
#include<iostream>
using namespace std;
int main(){
int a1=3; ///non-const data
const int a2=a1; ///const data
int * a3 = &a1; ///non-const data,non-const pointer
const int * a4 = &a1; ///const data,non-const pointer
int * const a5 = &a1; ///non-const data,const pointer
a5 = &a2; //error
*a4 = 13; //error
int const * const a6 = &a1; ///const data,const pointer
const int * const a7 = &a1; ///const data,const pointer
int * const a8 = &a2; //error,a8 points to non-const data and a2 is const
const int * a9 = &a2;
//*a9 = 10;
return 0;
}
示例的代码如上。总结,const修饰指针时,
- 位于 * 左边的是底层const,如 const int *,也就是表示指针所指数据是常量,不能通过解引用修改该数据;但是指针本身是变量,可以指向其他的内存单元。
- 位于 * 右边的是顶层const,如 int * const,也就是表示指针本身是常量,不能修改指针本身的指向。
- 当左右都有 const 时, 聪明的读者可能已经知道了,这时上述两个特点都具备,也就是指针本身是常量,指针指向的也是常量。
可能有人会记住这么复杂的规则,在这里介绍个小技巧,可以轻松记住。首先以 * 为分隔符,* 号 右边的 const 因为离 指针名近,所以它表示的是指针本身的const状态,为顶层const。 * 左边的const 离变量名远,所以他表示的是指向的对象的const状态,为底层const。
同时,从上述代码 a8 可以看出,a8所指向的a2是const 类型,所以 a8 的类型应该有一个底层const,代表它指向的是常量数据,底层const位于 * 左边,所以 a8 的类型可以是 const int * 或者 const int * const。在示例代码中a8的类型是int * const, 没有底层const,所以会报错。
2. const修饰函数参数
传递过来的参数在函数内不可以改变,与上面修饰变量时的性质一样。
void testModifyConst(const int _x) {
_x=5; ///error
}
3. const 修饰函数
class example{
public:
int a;
void test(int *p) const{
*p = 5; // ok
a = 1; // error
}
};
注意:const 修饰函数只能用来修饰成员函数,不能是不在类里面的普通函数,同样也不能是类的静态函数,下面会讲这样的原因。非静态的成员函数中都会有一个默认的 this 指针,指向一个实例,this指针默认是 <classname> * const this, 即 改变this的指向,加上 const 关键字之后 会给 this 指针 加一个底层const,即 this指针的类型变为 const <classname> * const this, 意味着不能通过 this 指针 去修改实例的属性。这里隐藏的一个知识点是实例的访问其实都是通过this指针访问的,如上所示 a = 1 这条语句 其实 是 this-> a = 1; 只是编译器替我们做好了这一部分工作。
此外,在写成员函数时一定要考虑是否要加const,不加const 意味着这个成员函数将无法应用于const 类型的实例,因为此时的this 指针类型是 <classname> * const this,而入的实例类型是 const <classname> a, 转换后的this指针类型是const <classname> * const this, 两者无法直接转换。所以要考虑这个成员函数是否需要作用在 const实例上 以及函数内部是否需要修改属性。
4. const 修饰函数返回值
待补充