• const限定符以及顶层const和底层const的理解


    一、const限定符的作用

      当我们在写程序的时候,想定义一种变量,它的值不会被改变,这时就可以用const限定符来定义变量,也可称它为常量,常量的定义必须要有初始值,否则编译错误。其实际例子是用一个变量来表示缓冲区的大小的时候。

      对内置类型用const是比较通俗易懂的,其作用就是不能对用const定义了的变量进行修改(写),但可以进行拷贝(读)。

    const int bufSize = 512;    //正确
    const int bufSize2;    //错误,const对象必须要初始化    
    int buffer[bufSize];
    
    const int a = 1;
    int b = 2;
    a = 3;    //错误,不能对常量进行赋值    
    b = a;    //正确

     

    二、const和引用

      在我的理解中,引用就相当于一个常量,它在初始化时就已经与一个对象绑定在一起,之后就不能绑定其他对象,这种专一的品质非常值得我们学习。而当用const对引用进行定义时,它的作用就是说明该引用绑定的对象是一个常量,不能对该引用进行修改(事实上,常量引用绑定的对象不一定是常量,常量引用中的“常量”这两个字的意思其实是引用觉得其绑定的对象是一个常量,但该绑定的对象是变量也是合法的,下面通过代码详细说明)。

    //非常量引用
    int a = 0;
    int &r = a;
    r = 1;    //通过操作引用来对a赋值,此时相当于a=1
    
    //常量引用绑定常量
    const int b = 1;    //b是一个常量
    const int &r2 = b;    //正确
    r2 = 5;      //错误,不能对常量引用进行修改
    b = 5;    //错误
    
    //常量引用绑定变量
    int c = 1;
    const int &r3 = c;    //正确,常量引用也可以绑定变量
    r3 = 5;    //错误,不可修改常量引用
    int d = r3;    //正确,常量引用可读,该值为c
    c = 5;    //正确,可修改变量
    
    //非常量引用不可绑定常量
    const int e = 1;
    int &r4 = e;    //错误

      以上四种情况已说明const和引用的关系,为何第四种情况中不可用非常量引用绑定常量呢,这是因为我们已经定义了e是一个不可修改的常量,假如我们用非常量引用成功绑定了它,并且可以通过修改引用来使e的值改变,这不就违背了e作为常量其值不可改变的理念了吗,所以第四种情况编译器是会报错的。

      常量引用中的const的作用是针对引用绑定的对象的,指所绑定的对象是一个常量,这叫做底层const。

     

    三、const和指针

      引用不是一个对象,因此const不能针对引用起作用,只能对引用的绑定对象起作用。但指针是一个对象,所以指针和const之间有三种组合方式:1.常量指针,2.指向常量的指针,3.指向常量的常量指针,其三者作用如下代码所示。

    //1、常量指针
    //常量指针指向变量,即常量指针中的地址不能修改
    int a = 1;
    int b = 2;
    int *const p = &a;    //正确,常量指针可以指向变量
    p = &b;    //错误,常量指针中的地址值不能修改
    *p = 2;    //正确,p的解引用是a的值,a是变量,可以修改该值
    
    //2、指向常量的指针
    //即指针中的地址可以修改,但指向的对象是常量不能用解引用修改值(实际上指向的对象可以是变量)
    int c = 3;
    const int d = 4;
    int e = 5;
    const int f = 6;
    int const *p2 = &c;    //正确,指向常量的指针可以指向变量
    const int *p3 = &d;    //正确,指向常量的指针指向常量
    p2 = &e;    //正确,可以改变指向的地址
    p3 = &f;     //正确
    *p2 = 0;    //错误,虽然p2实际指向的是一个变量,但操作p2的解引用时p2把指向的对象看作常量,因此不能通过解引用来修改对象的值
    c = 0;    //正确,不能通过p2的解引用修改c,但c自身是变量可以修改
    *p3 = 0;    //错误,同理p2
    f = 0;    //错误
    
    //3、指向常量的常量指针
    //即指针中的地址不可以修改,指向的对象是常量也不能用解引用修改值(实际上指向的对象可以是变量)
    int g = 1;
    const int h = 2;
    const int *const p4 = &g;    //正确
    const int *const p5 = &h;    //正确
    p4 = &h;    //错误,不能修改值
    *p4 = 0;    //错误,不能修改其解引用

      对象的类型确定了对象的操作,因此指向常量的指针它的“常量”两字不是限制指针指向的对象必须是常量,而是限制了指针的解引用操作。因为指向常量的指针和常量引用一样,是一个自以为是的家伙,它认为自己指向的一定是一个常量,所以对指向常量的指针进行解引用,让指针认为在对一个常量进行修改,因此这是非法的行为。

     

    四、顶层const和底层const 

    1、顶层const

      何为顶层const,其定义为对象本身是一个常量,因此对一切的内置类型常量而言,所有的const都是顶层const,而对于指针而言,常量指针是顶层const,对于引用则没有顶层const的概念,以下代码都是顶层const

    const int a = 1;
    const double val = 3.14;
    const string str = “hello”;
    int *const p = &a; 

      

      顶层const的对象一旦完成初始化,就不能修改其值,但可以作为被拷贝对象进行拷贝操作,如下代码所示。

    const int b = 1;
    b = 2;    //错误,顶层const不能修改值
    int c = b;    //正确,顶层const可以被拷贝
    int *const p2 = &b;
    *p2 = 0;    //错误,实际指向的为常量,不能修改其解引用
    p2 = &c;    //错误,顶层const不能修改值
    
    int *const p3 = &c;
    *p3 = 3;    //正确,实际指向的为变量,可以修改其解引用
    
    const int *p4 = p2;    //正确,顶层const可以被拷贝
    *p4 = 0;    //错误,p4是底层const(下面解释),不能修改其解引用

      

      有些朋友可能对const int *p3这句定义语句有疑问,其实它和int const *p3是一样的,都是指向常量的指针,也是一个底层const(下面介绍),而以上代码说明顶层const对象不能修改,但可以被拷贝,因为被拷贝的过程中,是可以忽略顶层const的。

    2、底层const

      底层const这个概念只在指针和引用上有效,其定义是该指针指向或该引用绑定的对象是常量。因此指针可以有顶层const和底层const,而引用只有底层const

    int a = 0;
    int const *p = &a;    //底层const
    const int &r = a;    //底层const

      很多朋友可能分不清一个指针到底是底层const还是顶层const,这里可以教大家一个方法,就是看变量名最近的声明符是什么,例如const int *p,最近的声明符是*,因此他是一个指针,第二个声明符才是const,因此他是一个指向常量的指针;又例如int *const p2,最近的声明符是const,因此p2是一个常量,第二个声明符才是*,因此它是一个常量指针。其实大家只要记住一个就行,各人有各人的方法,最紧要自己觉得好用啦。

      了解了底层const,那么我们分析一下底层const可以进行哪些操作,以下为代码。

    int a = 0;
    const int b = 0;
    int const *p = &a;    //底层const可以指向常量也可以指向变量,因为对于&a该类型可以从int*转换为const int*,因此可以说成对象被拷贝时可以忽略其顶层const
    
    //对于引用的底层const,即是常量引用
    const int &r = a;    //绑定一个变量
    r = 0;    //错误,引用的底层const不可以修改值。
    int c = r;  //正确
    const int d = r;    //正确
    int &r2 = r;    //错误
    const int r3 = r;    //正确  
    
    //对于指针的底层const,即指向常量的指针
    //修改指针的值
    p = &b;    //正确,指针的底层const可以修改值
    *p = 2;    //错误,指针的底层const不可以修改解引用的值
    
    //指针被拷贝
    int *p2 = p;    //错误
    int *const p3 = p;    //错误
    int const *p4 = p;    //正确
    const int *const p5 = p;    //正确,p5有顶层和底层const 

      对于引用的底层const,因为引用没有顶层const,对于它的操作特性,可以从它绑定了一个常量这个基础去理解,实际它不一定绑定常量,但在使用常量引用时要看成他始终绑定了一个常量,那么它的修改和被拷贝是否允许就比较清楚了。

      对于指针的底层const,指针把自己指向的对象视为常量,所以我们修改解引用的值时相当于修改指向的那个常量对象的值,这是不允许的,所以编译器报错。但指针不是常量指针(没有顶层const),因此可以修改指针的值(指向的对象可以改变)。当有底层const的指针用作被拷贝的对象是,其底层const就不能忽略了,拷入和拷出的对象必须都要有底层const才能对底层const指针进行拷贝操作。

      对指针const限定符的总结:

        1、顶层const不能修改值,但其解引用可能可以修改(根据实际指向的对象决定)

        2、顶层const作为被拷贝值时,没有限制,可以被忽略

        3、底层const可以修改值,但其解引用不能修改

        4、底层const在用作拷贝操作时,要求拷入与拷出值都有相同的底层const(都是底层const,或都不是),不能忽略。

  • 相关阅读:
    ASP.NET 表单验证 Part.2(实现表单验证)
    长工的买房故事
    软件界面交互和易用性改进总结[zz]
    访问hotmail邮箱的途径
    Google内部收集员工创意的方法[转载]
    Web2.0地图展望
    C++开源跨平台类库集
    庆祝lucky荣登早教网首页宝宝
    在那些打磨汉芯的日子里[转贴]
    在中国搞技术只能混碗饭吃,没有太大希望
  • 原文地址:https://www.cnblogs.com/qjswxd/p/10415939.html
Copyright © 2020-2023  润新知