C++关键字之const

const即constant的缩写,意为持久不变的.

1.通过const修饰来定义常量

在常量定义前加const,可以使定义的常量只读,不能修改.如:

int main(){
    const int a = 12;
    a = 13;//编译报错:表达式必须是可修改的左值
    cout<

2.const修饰指针

const修饰指针有三种情况.

(1)const修饰指针

当以下面形式声明指针时,则为const修饰指针,声明的指针p为常量指针.

int main() {
    
    int a = 12;
    const int* p = &a;//p为常量指针
    return 0;
}

常量指针:指针指向的是常量.即指针的指向可以修改,但指针指向的值不能修改.

int main() {
    
    int a = 12;
    int b = 10;
    const int* p = &a;//p为常量指针
    *p = b;//错误,试图修改指向的值.编译报错:表达式必须为可修改的左值
    p = &b;//正确,修改指针的指向,可以通过编译
    return 0;
}

(2)const修饰常量

当以下面形式声明指针时,则为const修饰常量,声明的指针p为指针常量.

int main() {
    
    int a = 12;
    int* const p = &a;//p为指针常量
    return 0;
}

指针常量:指针本身为常量.即指针指向的值可以修改,但指针的指向不能修改.

int main() {
    
    int a = 12;
    int b = 10;
    int* const p = &a;//p为指针常量
    *p = b;//正确,修改指针指向的值,可以通过编译
    p = &b;//错误,试图修改指针的指向,报错:表达式必须为可修改的左值
    return 0;
}

(3)const既修饰指针,又修饰常量

当以下面形式声明指针时,则为const既修饰指针,又修饰常量.

int main() {
    
    int a = 12;
    const int* const p = &a;
    return 0;
}

指向的值和指针的指向都不能改变.

int main() {
    
    int a = 12;
    int b = 10;
    const int* const p = &a;//p为指针常量
    *p = b;//编译不通过
    p = &b;//编译不通过
    return 0;
}

(3)const修饰指针总结

image-20210906151455637.png

3.const修饰引用

const修饰引用的情况只有一种,即:

int main() {
    int a = 12;
    const int& r = a;
    int& const r = a;//这样写跟不加const没区别
    r = 10;//编译不通过,r为常量不能修改
    return 0;
}

当用const修饰引用时,可以直接赋右值给引用.

int main() {
    int& r = 10;//编译不通过,必须赋左值
    const int& const_r = 10;//编译通过
    //使用常量(字面量)对const引用进行初始化时,C++编译器会为常量值分配空间,并将引用名作为这段空间的别名
    //int temp = 10;
    //const int &ci = temp;
    return 0;
}

4.使用场景

(1)定义全局常量

类似于define宏定义,将不会变的常量进行定义,方便调用.如:

const double PI = 3.14159625;
int main(){
    return 0;
}

(2)修饰形参

当我们需要传递一个较大的对象给函数作为参数时,为了节省内存,可以将函数参数定义为指针或者引用类型,然后将对象的指针或引用传递给参数即可.为了防止函数中对形参进行修改(因为这样会影响到实参),一般将形参加上const修饰符,从而使其变为只读.如:

struct User {
    int uid;
    string pwd;
};
void user_print(const User& user) {
    user.uid = 300;//编译不通过
    cout << "uid: " << user.uid << endl;
    cout << "pwd: " << user.pwd << endl;
}
int main() {
    User user = { 316,"123456" };
    user_print(user);
    return 0;
}

5.面向对象中的const

(1)const修饰成员函数

  • const修饰的成员函数称为常函数
  • 常函数内不可以修改成员属性
  • 成员属性声明时加关键字mutable后,在常函数中依然可以修改
class A {
private:
    int a;
    mutable int b;
public:
    void show_A() const{
        a = 10;//无法通过编译
        b = 20;
    }
};

本质:每个成员函数都有一个隐藏的参数,即this指针,this指针的本质就是一个指向自身对象的一个指针常量(Type* const this),所以this指针的指向不会变,永远指向自己.给成员函数加const修饰相当于给this指针又加上了const修饰指向的值,即(const Type* const this),这样,this指针的指向不会变,指向的值也不允许改变.

(2)const修饰对象

  • 声明对象前加const称该对象为常对象
  • 常对象只能调用常函数,普通对象既可以调用普通成员函数,也可以调用常函数
  • 常对象不能修改属性
class A {
private:
    int a;
    mutable int b;
public:
    void show_A() const{
        
    }
    void show() {
        
    }
};
int main() {
    const A a;
    a.show_A();//正确
    a.show();//错误
    return 0;
}

6.const与define宏定义的区别

  • 作用阶段:define只在预处理阶段起作用,而const在编译和运行阶段起作用.因此,const可以进行调试而define不行;
  • 作用方式:define为简单的字符串替换,const有类型检查,因此const比define更安全,不易出错;
  • 存储方式:define只是进行展开,有多少地方使用,就替换多少次,它定义的宏常量在内存中有若干个备份;const定义的只读变量在程序运行过程中只有一份备份。所以const比define要节省内存.

结论:⚡const⚡与⚡define⚡相⚡比⚡,那⚡我⚡还⚡是⚡感⚡觉⚡我⚡们⚡const⚡牛⚡逼⚡

7.const_cast

const_cast用于去除const限定,但其目的并不是修改const修饰的变量(而且也修改不了)

使用场景举例:

我们可能调用了一个参数不是const的函数,而我们要传进去的实际参数确实const的,但是我们知道这个函数是不会对参数做修改的。于是我们就需要使用const_cast去除const限定,以便函数能够接受这个实际参数。如:

void fun(int* a) {
    //*a++;
    cout << *a;
}
void main(){
    const int constant = 12;
    int* p = const_cast (&constant);//通过const_cast去除const限定
    fun(p);
}

传统转换方式实现const_cast

const int constant = 12;
int* p = (int*)&constant;//直接通过显示转换,强转指针类型

详见:https://www.cnblogs.com/ider/archive/2011/07/22/cpp_cast_operator_part2.html

参考文章:https://blog.csdn.net/weixin_38279101/article/details/112355990

https://blog.csdn.net/weibo1230123/article/details/81981384

你可能感兴趣的:(C++关键字之const)