关键字const

引言

  在C和C++中,限定符const的应用可谓十分常见。我在重现教材书籍code的时候,老是在const的问题上犯迷糊。今天刚忙完导师布置的任务,闲着就像把这个问题说清楚,以后自己再有问题也好自我反省下。

  首先在C语言中,const是一个限定符,它用来限定一个变量不被改变。使用const在一定程度上可以提高程序的健壮性,另外,在观看别人代码的时候,清晰理解const所起的作用,对理解对方的程序也有一些帮助。那么具体来看,const被用在什么地方呢。

  我将从以下4点来讲解const限定符的用法:

          1、对象与const

            2、引用与const

          3、指针与const  

          4、函数与const

1、对象与const

  这是最直观的用法。比如我们有以下代码:

       const int bufSize = 512;

     定义bufSize为常量且初始化为512。此后,任何尝试修改bufSize的尝试都会导致编译错误,例如 bufSize = 100; 

  此外,还要注意的是:

       const  std::string hi = "hello!";  //正确
       const  int i, j = 0;               //错误,i 没有初始化

    因为作为const常量在定义后就不能修改,所以定义时必须初始化。

2、引用与const

  先复习一下引用。引用就是它绑定的对象的另一个名字,例如:张三有个小名“阿三”,叫“阿三”就是叫张三这个人,那么“阿三”就是张三的别名,即引用。

  引入const后,引用有了一些有趣的规则,这里讲一下。

  const引用:const引用是指向const对象的引用,例如:

    const int r = 100;    
    double r1 = 100.0;
    const int &p1 = r;      //正确,const引用可以绑定到const对象上
    const int &p2 = r1;     //正确,const引用可以绑定到数据类型相关的const对象上
    const int &p3 = 100;    //正确,const引用可以绑定到右值

    与之对应的,非const的引用只能绑定到与该引用相同类型的对象上。

3、指针与const

  同样简单先复习一下指针的知识。指针也是一种变量,它保存的是一个对象的地址(注意:指针也有自身的地址,该地址中的数据就是该指针指向的地址)。

  指针与const关系比较复杂,我这里借鉴《C++ Primer》上的顺序,非3小点来解释这个问题。

  1)指向const对象的指针

  我们知道,指针可以用来修改它所指向的对象的数据。但是如果它指向一个const对象,那么自然不允许被修改。C++语言中强制要求:指向const对象的指针必须具有const特性。

  for example:

     const double *pt;    //a point to a double that is const

  这里的pt是指向一个const对象的指针。值得注意的是,这里仅仅说明了这个指针指向的数据类型,而没有说这个指针本身就是const,因此定义的时候也不一定要初始化,同理如果有必要,还能在接下来的代码中将pt指向其他的const对象。指针本身是const会在接下来的几点中讲到。

  这个规则对void指针也成立,即:必须使用const void*类型的指针保存const对象的地址

      但是,C++允许把非const对象的地址赋给指向const对象的指针,例如:

    double  dval = 3.14;
    const double *pt = &dval;

  这样一来,不能通过指针pt来修改dval,但是仍然可以直接修改dval。

  《C++ Primer》上有句话也许可以用来帮助记忆这个“指向const对象的指针”:这种指针可以理解为“自以为指向const的指针”

  2)const指针

  上一点中,指向const对象的指针不能说明指针本身就是const,那么const指针就是说:指针本身就是const的,不能用它来指向初始化对象以外的对象

  const指针语法格式:

    int  errNumb = 0;
    int *const curErr = &errNumb;

 

     可以看到,这种指针必须初始化。但是同样的,const指针并没有说明:能否使用该指针来修改它指向的对象的值。能否修改取决于该对象的类型。

  3)指向const对象的const指针

  有了前两点的铺垫,这种指针就很好理解了。

    const double pi = 3.14159;
    const double *const pt = π

  这里,pt既不能修改pi的值,也不能更改pi的指向。我们可以从左到右阅读上述的声明语句:

         pt首先是一个const指针,指向double类型的const对象

     P.S 在《C++ Primer》上有这么一个例子值得讨论,这里拿来讲下。假设有下面的句子:

    typedef string *pstr;
    const pstr cstr;

  问这里的csr变量是什么类型的。很多人看到这里,都会认为第二句是这么展开的 const string *cstr; 因此它就是一个指向string类型的const对象的指针。这其实是错误的认识,这种错误源自于认为typedef单纯的是做文本扩展了(文本扩展那是宏定义的事)。这里应该这么理解:

  const修饰的是pstr类型,而pstr是什么类型呢?typedef告诉我们它是一种string*,就是指向string类型的指针,那么这里的cstr就是一种指向string类型的对象的const指针。即第二句应该这么还原: string *const cstr; 

  这里同时也是告诉我们,typedef做的事情是对类型的提升

4、函数与const

  有了前面3点的铺垫,函数的const就很好理解了,直接举个例子吧

    const int  func(const int &a) const{
              ...
    }

 

  函数返回一个const对象,他的参数是一个const的引用,它是一个const的常量函数,也就是说,该函数不会修改调用函数的实参。

 5、后记

  今天刚好遇到一个const常量成员函数的问题,不妨贴上来和大家分享下。

  错误代码是这样的,有兴趣的可以拿回去编译下。

 1 #include<iostream>
 2 using namespace std;
 3 
 4 class Point3d{
 5     public:
 6         Point3d(float x=0.0, float y=0.0,float z=0.0)
 7             :_x(x), _y(y), _z(z){}
 8             
 9         float x() {return _x;}
10         float y() {return _y;}
11         float z() {return _z;}
12     private:
13         float _x,_y,_z;
14 };
15 
16 inline ostream&
17 operator<<(ostream &os, const Point3d &pt){
18     return os<<"("<<pt.x() << "," <<pt.y() <<"," <<pt.z() << ")"; 
19     
20 }
21 
22 int main(){
23     Point3d pd(1,2,3);
24     cout<<pd;
25 }

  我使用DEV给我报的错的这样的:

 

 

  

 也就是说:

    不能将“this”指针从“const Point3d”转换为“Point3d &”----转换丢失限定符

 简而言之,第17行重载的<<操作符使用了const Point3d对象,那么const对象必须调用const成员函数,于是我的x(),y(),z()都没有声明成const函数,于是报错。

 在这里我们把每个函数填上const限定符就能解决了。

posted @ 2016-11-09 15:15  Holy炭  阅读(260)  评论(0编辑  收藏  举报