const关键字用于表示变量或函数, 亦或其他类型的数据其值或其本身的值禁止被修改.
但需要注意的是, 即使被修饰为const类型的变量, 其本质依旧是个变量, 而不是常量.
也许你会说, 这有什么区别呢? 我在代码中感觉不出差别啊. 其实它们的差别在于编译器的编译. 对于编译器来说, 变量意味着需要分配内存空间, 而常量只是在编译期间记录在编译器的一张内存表里面的一个证整数而已. 变量的值必须初始化, 除非使用extern修饰它, 这就告诉编译器该变量是一个全局const变量, 在哪里定义编译器暂时不知道, 所以允许它在其他地方定义其值, 一旦定义好后就禁止再次修改了.
比较复杂的情况, const修饰变量意外的情况:
1. char * const x = "diamond"; // x 禁止修改, 但是*(x)可以被修改: *x = "kongdom"; OK | x++; ERROR!!!
2. const char *s = "diamond"; // *(s) 禁止修改, 也就是该字符串禁止被修改: *s = "kingdom"; ERROR!!! | s++; OK
3. Person P_01;
const Person *p = &P_01; // 对象是const
Person const *p = &P_01; // 对象是const
Person *const p = &P_01; // 指针是const
const Person *const p = &P_01; // 对象和指针都是const
那么到底什么情况下建议使用const呢?
1. 修饰函数参数:
大家都知道在c++的函数传参中, 有值传递, 引用传递和指针传递三种形式. 当使用后两者进行参数传递时, 函数被调用后, 实参的值会被函数内部的操作修改, 那么如果不需要修改呢, 是不是传引用和指针就无法搬到了呢? 答案当然是否定的, 这个时候你只需在函数参数列表中使用const来修饰变量就可以了.例如:
void func_01(const int *x); // 这里编译器将禁止修改传进函数中的, 这个指针所指向的内存空间中的值
int a = 100;
func(&a); // 将a压栈
const int b = a; // 将a的值放入b中
func(&b); // 将b压栈
b = a++ // ERROR! b的值禁止被修改
void func_02(const int i)
{
i++; // ERROR! i的值禁止被修改
}
2. 修饰成员函
这意味着this是const
int get_age() const;
int Student::set_age(int age)
{
this.age = age;
}
int Student::get_age() const
{
this.age++; // ERROR! 禁止修改成员变量
set_age(16); // ERROR! 禁止调用没有cosnt修饰的成员
return age; // OK
}
3. 修饰类的对象
对象里面的值禁止修改
4. 关于函数重载
设: 某class Student内有如下成员函数:
void func();
void func() const;
且: 在main()函数中有:
const Student stu;
stu.func();
则: 以上两个函数构成函数重载, 可以实现静态多态.
也许你会问, 这两个函数应该是被重复定义了啊, 应该是错误的. 它们无法构成函数重载. 但实际上不是这样的.
这里的两个func()函数, 都属于类的成员函数, 而它们实际上是这样的:
void func(Student *this);
void func(const Student *this);
也就是说, 第二个func()函数的修饰符const, 是用来修饰类的对象本身的, 也就是this
当const 类型的对象 stu, 调用func()函数时, 就会去调用同样是const类型的那个func() const函数.