不同const的作用
一、针对普通变量
1. 直接修饰普通变量
表示被修饰变量为常量,具有不可修改的特点。
const int a = 10;
2. 用于表征一些常量参数,方便展示其含义
与普通常量用法完全一样,同时使常量含义清晰,需要调整该常量值时,不必在程序中一个一个值修改,只要修改定义的常量值即可,使调试更方便且更安全。
3. 便于进行类型检查
使编译器对处理内容有更多了解,消除了一些隐患。编译器就会知道i是一个常量,不允许修改;
void f(const int i) {
// 函数内容
}
二、针对函数或者成员函数
1. 修饰函数形参
函数定义和声明时放在形参前,表示该参数传入后在函数内部不允许更改
void func(const int a){
a = 10; // 错误,传入参数a不允许修改
)
2. 修饰函数:修饰函数返回值
若函数返回值为一个对象的引用,则在没有const修饰情况下,可以通过返回的引用修改引用对象的值. 尤其是在面向对象编程中,很容易误改实例的属性值。
#include "iostream"
int a = 10;
int& get_a(){
return a;
}
const get_a_2(){
return a;
}
int main(){
std::cout << "hello world" << std::endl;
get_a() = 20;
// 输出 20
std::cout << get_a() << std::endl;
get_a_2() = 30; // 报错, 表达式必须为一个可修改的左值,通过const修饰返回值,使其不可通过函数返回值修改
return 0;
}
3. 修饰成员函数函数体
这种情况下const位置是函数体前,函数参数列表后,表示该成员函数不修改成员变量。
class A{
private:
int a_;
public:
void func() const {
int s = a_; // 正常读取
s = a_ * a_; // 临时变量可以修改
a_ = s; // 报错,该函数体不允许修改成员变量
}
};
三、针对指针
共分三种写法,但实际上是两种情况。如下情况:
int a=10;
int b=100;
// 情况一
const int *p1 = &a;
int const *p2 = &a;
// 情况二
int * const p3 = &a;
1. 修饰指针所指向的变量
这种情况下,指针本身指向的地址是可以修改的,但是指针指向地址的变量不允许通过该指针修改,即*p的值被const修饰,因此不允许修改 *p ,但是可以修改 p 本身的值,即可以改变 p 的指向。包括通过->进行成员变量的修改也同样是不被允许的。
以上述代码片段举例:
*p1 = 20; // 错误,*p1 不允许修改
*p2 = 30; // 错误,原因同上
p1 = &b; // 正确,p1本身允许改变
p2 = &b; // 正确,原因同上
2. 修饰指针变量本身
这种情况下指针指向地址的变量值可以改变,但是指针本身指向的地址不可变。即 const 修饰的是指针变量 p,因此只限定 p 的值不允许修改,即指针指向的地址不可变。但是对应地址上存储什么值,不受这类const限制。
以上文代码片点为例:
p3 = &b; // 错误,p3不可变
*p3 = 300; // 正确,p3对应地址的值不受限制
3. const指针总结
总的来说,要判断const修饰指针的情况,主要可以通过观察 const 和 * 的位置来判断修饰的是 *p 还是 p 来判断,若const在 * 前,则说明 const 修饰 *p, 否则修饰 p。