1.修饰变量
const int i = 0; // i 为常量,不可修改 const int* p = &i; // 指向常量的指针 int* const p = &i; // 指针为常量,指向i不可修改 const int &r = i; // 常量引用,不可通过r修改i typedef int *po; const po p = &i; // 此时const修饰的是 int* ,所以此时指针是常量
顶层const:指针本身是常量
底层const:指针所指向的对象是常量
2.修饰函数(包括返回值,参数,函数体)
const int fun(){...} // 函数返回值为常量 void fun(const int a, const int b){...} //函数参数为常量
const如何修饰函数体(主要修饰类的成员函数):
class TestClass { public: TestClass() : val(100) {} ~TestClass() {} int getVal_v1() { return val; } int getVal_v2() const {
// val ++; 编译报错,常量成员函数不可修改数据成员 return val; } private: int val; }; int main() { TestClass t; int a = t.getVal_v1(); // 正确,非常量对象调用非常量成员函数 int b = t.getVal_v2(); // 正确,非常量对象调用常量成员函数 const TestClass tc; int a = tc.getVal_v1(); // 编译报错,常量对象不可调用非常量成员函数 int b = tc.getVal_v2(); // 正确 return 0; }
从上边代码中可以得到两个结论:
- 类中的常量成员函数不可修改数据成员
- 类的常量对象不可调用非常量成员函数
上边我们只得到了结论,但是深层次的原因是什么呢?我们还要从this指针说起。。。
当我们通过对象调用类的成员函数时,成员函数是如何找到类的数据成员的呢?比如上边代码中的t.getVal_v1(); 这句代码可以等价为 t.getVal_v1(this); 在调用过程中编译器会将this指向调用对象 this = &t; 然后在成员函数内部,通过this指针来获取数据成员。
但问题就出在this是一个常量指针,指向某个对象后,就不可以再指向别的对象。在成员函数的参数列表后加一个const就是用来修饰this的,使得this从常量指针变为常指针常量,也就是指针以及指针所指向的对象都是常量。
所以在 getVal_v2() 成员函数中,不能通过常指针常量 this 修改数据成员。
将对象定义为const常量之后,那么非常量指针this是不能指向该对象的。
但 常量成员函数不可修改类的数据成员 这句话并不绝对,因为有 可变数据成员 mutable,如下例所示:
class TestClass { public: TestClass() : val(100) {} ~TestClass() {} int getVal_v2() const { val ++; // 正确,因为val是可变数据成员 return val; } private: mutable int val; };