美文网首页
C++ const 关键字

C++ const 关键字

作者: long弟弟 | 来源:发表于2022-07-29 21:20 被阅读0次

    本文是对const关键字的一个简单总结,测试环境IDE的是Xcode13.2.1

    一、const及常量指针、指针常量、常指针常量

    const是常量的意思,表示被修饰的变量不可修改
    如果修饰的是类、结构体(的指针),其成员也不可以更改

    先说结论:const修饰的是其右边的内容

    验证:

    #include <iostream>
    using namespace::std;
    //以下使用结构体验证(类与结构体的差异在C++中,只是访问权限的不同)
    
    struct Date {
        int year;
        int month;
        int day;
    };
    
    int main(int argc, const char * argv[]) {
        // insert code here...
        const int age = 10;
        //int *a = &age; //“const int *”类型不能初始化“int *”类型
        //age = 20; //const修饰的变量不能修改
        //const int age1; //const修饰的类型必须在初始化时进行赋值
        
        Date date1 = {2021, 1, 2};
        const Date date2 = {2022, 2, 3};
        //date2 = date1; //const修饰的结构体本身不能被赋值
        //date2.year = 2019;//const修饰的结构体成员不能被赋值
        
        
        const Date *p = &date1;
        cout << "ori:" << p->year << p->month << p->day << endl;
        //p->year = 2011; //const修饰的是指针p,那么指针p即*p是不能改变的,但是p是可以修改的
        //(*p).month = 4;
        //*p = date2;
        p = &date2;
        cout << "modify:" << p->year << p->month << p->day << endl;
        
        //Date *date3 = &date2;//'const Date *'类型不能初始化'Date *'类型
        //与int *a = &age;同理
        
        int height = 10;
        int money = 20;
        {
            int *pp = &height;
            *pp = 30; //height = 30;
    
            pp = &money;
            *pp = 40; //money = 40;
        }
        cout << "height:" << height << endl;
        cout << "money:" << money << endl;
        const int *p0 = &height;
        int const *p1 = &height; //变量类型和const可以交换, p0和p1没有区别
        {
            const int *pp0 = &height;
            //*pp0是常量,pp0不是常量,常量指针
            cout << *pp0 << endl; //10
            //*pp0 = 50;//Read-only variable is not assignable
            pp0 = &money;
            cout << *pp0 << endl; //20
        }
        int * const p2 = &height;
        {
            int *const pp2 = &height; //pp2是常量,*pp2不是常量,指针常量
            *pp2 = 60; //height = 30;
            
            //pp2 = &money; //Cannot assign to variable 'pp2' with const-qualified type 'int *const'
        }
        cout << "height:" << height << endl;
        cout << "money:" << money << endl;
        
        const  int * const p3 = &height;
        int const * const p4 = &height;
        //p3和p4等价
        {
            const  int * const pp3 = &height;
            //第一个const修饰*pp3,*pp3的内容不能改 *pp3是常量,常量指针
            //第二个const修饰pp3,pp3的内容不能改 pp3也是常量,指针常量,常指针常量
            //*pp3 = 70;//Read-only variable is not assignable
            //pp3 = &money;//Cannot assign to variable 'pp3' with const-qualified type 'const int *const'
        }
        
        return 0;
    }
    

    问题:

    以下五个指针分别是什么含义?

    const int *p0 = &height;
    int const *p1 = &height;
    int * const p2 = &height;
    const  int * const p3 = &height;
    int const * const p4 = &height;
    

    参考答案:
    p0和p1等价,是常量指针
    p2是指针常量
    p3和p4等价,是常指针常量

    二、const Reference常引用

    前提

    引用的本质就是指针,只是编译器弱化了它的功能,所以引用就是弱化了的指针

    引用可以被const修饰,这样就无法通过引用修改数据了,可以称为常引用
    const必须写在&符号的左边,才算是常引用

    const引用的特点

    1. 可以指向临时数据(常量、表达式、函数返回值等)
    2. 可以指向不同类型的数据
    3. 作为函数参数时(此规则也适用于const指针)
      可以接收const和非const实参(非const引用,只能接收非const实参)
      可以跟非const引用构成重载

    了解:

    当常引用指向了不同类型的数据时,会产生临时变量,即引用指向的并不是初始化时的那个变量(汇编)

    #include <stdio.h>
    #include <iostream>
    using namespace::std;
    
    int test1() {
        return 100;
    }
    //这里sum参数要求必须是引用类型
    //引用接收的是变量
    int sum(int &v1, int &v2) {
        cout << "sum(int &v1, int &v2)" << endl;
        return v1 + v2;
    }
    //引用变成常引用就可以接收常量了,常引用可以接收变量和常量
    int sum(const int &v1, const int &v2) {
        cout << "sum(const int &v1, const int &v2)" << endl;
        return v1 + v2;
    }
    //以上两个sum函数构成重载,换成*指针也使用,去掉引用或指针就报错
    int main(int argc, const char * argv[]) {
        // insert code here...
        int age = 10;
        int height = 10;
        
        int &ref = age; // ref相当于age的别名,ref作为引用不能再指向其他变量(即不能当其他变量的别名)
        //&ref = height;
        
        ref = 20;
        cout << "age:" << age << endl << "ref:" << ref << endl;
        //常引用
        const int &ref2 = age;
        //int const &ref2 = age; //等价上一句
        //ref2 = 30; //不能再赋值
        cout << "ref2:" << ref2 << endl;
        //int & const ref3 = age;//Xcode报错:'const' qualifier may not be applied to a reference//'const'不能修饰引用 //VS编译器 可以编译通过 但因为引用指向本身不可更改,所以这里的const没有意义,等价于int &ref3 = age;
        
        //int *const p3 = &age;
        //p3是常量,p3不能修改,*p3可以修改即可以通过p3间接修改
        //可以把引用当做指针来看,所以在VS中可以ref间接修改,本来就是间接修改,所以没意义,可能是这个原因所以Xcode编译器直接报错
        
        //ref3 = 40;
        
        //int &ref4 = 10; //默认引用指向变量,因为本质是指针
        const int &ref5 = 10; //常引用可以指向临时数据(常量)
        int a = 1;
        int b = 2;
        const int &ref6 = a + b; //常引用指向表达式
        const int &ref7 = test1(); //常引用指向函数返回值
        const double &ref8 = age; //常引用指向了不同类型的数据
        
        cout << sum(a, b) << endl; //v1引用a
        //sum(10, 20); //v1引用10?
        //v1引用10的话,形参必须是const int &v1
        cout << sum(10, 20) << endl;
        const int c = 3;
        const int d = 4;
        cout << sum(c, d) << endl;
        
        age = 30;
        cout << "age:" << age  << "ref2:" << ref2 << endl;
        //引用的本质是指针,age变了,别名也变
        //输出age:30ref2:30
        cout << "age:" << age << endl << "ref8:" << ref8 << endl;
        //输出age:30ref2:20,ref8指向不同数据类型产生临时变量
        return 0;
    }
    

    三、const成员

    const成员:被const修饰的成员变量、非静态成员函数

    const成员变量:

    必须初始化(类内部初始化),可以在声明的时候直接初始化赋值
    非static的const成员变量还可以在初始化列表中初始化

    const成员函数(非静态):

    1. const关键字写在参数列表后面,函数的声明和实现都必须带const//限制修改(非静态)成员变量
    2. 内部不能修改非static成员变量
    3. 内部只能调用const成员函数,static成员函数
    4. 非const成员函数可以调用const成员函数
    5. const成员函数和非const成员函数构成重载
    6. 非const对象(指针)优先调用非const成员函数
    7. const对象(指针)只能调用const成员函数、static成员函数
    class Car {
    public:
      const int m_price = 0;
      Car(): m_price(0) {}
      void display() const {
         cout << "price is " << m_price << endl;
      }
      void run() const;
    };
    void Car::run() const {
      cout << "Car::run()" << endl;
    }
    

    四、类型转换

    static_cast<type>(expression)
    //对比dynamic_cast,缺乏运行时安全检测
    //不能交叉转换(不是同一继承体系的,无法转换)
    //常用于基本数据类型转换、非const转成const
    dynamic_cast<type>(expression)
    //一般用于多态类型的转换,有运行时安全检测
    reinterpret_cast<type>(expression)
    //属于比较底层的强制转换,没有任何类型检查和格式转换,仅仅是简单的二进制数据拷贝
    //可以交叉转换
    //可以将指针和证书互相转换
    const_cast<type>(expression)
    //一般用于去除const属性,将const转为非const
    

    相关文章

      网友评论

          本文标题:C++ const 关键字

          本文链接:https://www.haomeiwen.com/subject/xvtpbrtx.html