C++ 中const关键字用法小结

        相对于C语言中,const关键字只用来修饰一个赋值后不可再改变的变量,C++中的const用途要多很多,也容易搞混。看了两遍C++编程思想的常量章节,将自己的理解做一个记录。

        一、定义常量

        1、指定类型和不指定类型

        在定义常量的时候,加上类型很好理解。比如const int a; 说明常量a是整形的。

        编程思想中举例定义常量时可以不指定类型,但在VC++2005中是不能编译通过的,在VC6中倒是可以,但只不过默认是个int而已,所以,定义const变量时,一律指定数据类好了。

        2、定义在.cpp还是.h中

        1)在不同.cpp中定义相同名字的常量,只有当前文件中定义的有效。只是使用常量值,编译器并不会为这个常量分配空间,而是在编译时直接用立即数代替。其实即使分配了空间,也是当做编译时常数用的,在汇编中也是立即数。应该简单类型常数都可以这样用。

        2)在一个.cpp中定义,.h中声明常量,那么即使多个.cpp都用到了这个常量,那也只能以唯一一处定义为准,这没什么好说的。如果需要为这个常量分配内存,那么就分配一个内存。

        3)在.h中定义,多个.cpp中使用的常量。如果需要分配内存(比如明确要取这个常量的地址),那在每个文件中,都会分配一个内存的,其实就变成多个相同名字的常量了。

 

        二、常量作用

        1、最基本的作用之一,代替#define。

        2、最基本的作用之二,在定义变量时指定值,不允许再变化了。

        简单类型的常量,不管是用于1还是2,不管是不是分配了内存,都可以作为编译时常数使用,比如定义数组大小。但是如果是自定义的类型,则一定会分配空间,且不能作为常数使用,只是不能改变而已。

        3、函数的参数使用const

        参数列表中的参数如果用const修饰的话,在函数中就不能够被修改。

        分两个角色来看:

        1)函数提供者,使用const参数,可以避免在函数体中无意改动到传入的参数。

        2)函数使用者,调用函数式,如果参数类型是指针的话,比如const int *para,那么可以放心,函数不会修改到传入地址中数据。

        4、函数的返回值使用const

        函数返回值是const,那么这个返回值不能改变。

        如果返回值是简单类型,其实本来就不可以再被修改;如果是自定义类型,倒是有些用,比如有函数 const MyClass* GetInstance(),那么 GetInstance()->func()这样的操作是不允许的,如果func()不是一个const方法。这样可以允许程序中存在一些只读对象,保存重要的信息。

       特别说明一下,这样的用法是可以的:

       const MyClass GetInstance();

       MyClass a = GetInstance();

       a.value = 10;

       我理解=号在这里做了一个拷贝操作,把GetInstance()返回的对象拷贝给了a,这个拷贝操作与返回值的const属性不冲突,后面修改a也与GetInstance()的返回类型无关。

       这样我也可以理解为何一个const int *const f();可以这样用:const int * p = f(); f()返回一个常量指针,指向一个常量地址,那么因为返回时,把指针的值赋值p,并不影响int *const这个属性。而因为这个指针指向的地址中的内容是const的,所以只能赋值给一个同样是 const int *的指针(变量地址可以给指向常量的指针,常量地址不能给指向变量的指针)。

        三、指针常量

        主要是两种修饰:

        1、const int * p  和  int const *p 表示p是个指针,指向一个常量地址。而P的指向,本身是可以变的。

        2、int * const p 表示p是个指针,p本身是个常量,其值初始化后不可变,但其指向的地址中的内容是可以变的。

        这个就有点绕了,比如 int a, *b; 表示a是普通变量,b是指针变量,那么*应该是跟随变量名的。但是从int * const p 来看,p是指向int的指针,p是常量,那么*又是跟随int的……也只能接受了。

        说明:虽然const int *p = &a;后, *p = 1;是非法的,但是a=1;是OK的,另外拿一个int *q = &a; *q = 1;也是OK的。

 

        四、类中的常量成员

        在类中定义常量,我想无外乎两个目的:

         1、使成员值不可修改

          一个成员变量使用const 后,所有成员函数不能修改他,对象的使用者也不能修改他(public属性的成员)。

          const的成员变量初始化必须放在构造函数的初始化表中,不能在函数体里来完成。也不能不初始化。那么,只要有常量成员的类,都必须自定义构造函数了。

          PS:C++中的指针几乎是万能的,这样:

         class MyClass
         {
                const int a;
                void SetA(int n)
               {
                   //a = n; 这样肯定不行
                   int *p = (int *)this;
                   *p = n;     // 这样就可以了 
               }
         }

        这种做法可以绕过const的限制,但……好像也没有办法啊。

 

         2、用来作为类中一个常数

          一般用来定义数组长度吧?但不好意思,用const不好使。

          class MyClass
          {
              const int size = 100;

              int arr[size];
          }

          这样行不通,因为size是属于对象的,每个对象都有一个,其值不能在编译时确定。其实 const int size = 100;这一句都是编译不过的。

          所以,得用enum来搞:

          class MyClass
          {
              enum {size = 100}
              int arr[size];
          }

          那么,既然不能用const int size是因为这个常量是属于对象的,那我搞一个static const能不能实现目的呢?这个是类的了。

          class MyClass
          {
              static const int size;
              int arr[size];
          };
          const int MyClass::size = 100;

          编程思想上倒是有说这个,但在VC6和VC2005上都还是行不通的。

 

        五、常量对象

        自定义类型后,用这个类型定义的变量,就有可能是const的。

         const对象的成员不能被修改,而且为了避免通过成员函数修改到成员变量,连成员函数都是不可以调用的(除非用const来修饰成员函数)。

         这里有个小思考:既然类中有常量成员,编译器可以阻止成员函数修改之,那如果对象是const的,那编译器只要阻止成员函数修改所有成员变量就行了,为什么连函数都不能调用呢?

         至少有一个原因,对于类型提供者来说,不知道用这个类型定义的对象是否const,因此编译类的时候,编译器无法限制修改成员。而类型使用者,编译的时候也不知道哪个成员函数修改了成员。

         const函数不能修改成员,编译器会阻止;再把不修改成员的函数加上const属性。这样的话,提供一个类,就可以根据需要定义const对象,而且对象中的数据也可以通过成员函数来读取了(要是没有const函数,那只能把成员变量定义成public的了,这破坏了封装)。

         构造函数和析构函数因为几乎肯定要修改到成员变量,所以不能是const的。而const对象也必须构造和析构,所以这两个函数不受限制。实际上,const对象更依赖于构造函数来初始化成员。我们定义类型的时候,因为不知道是否会出现const对象, 因此还是尽量定义好构造函数,做必要的初始化吧。

        mutable关键字

        用来修饰即使在常量对象中,也能够修改的成员。const函数也能修改之。

        这样选用mutable和const成员:

        1、要是类中有少数成员是无论如何不能修改的,用const

        2、要是类中有少数成员是无论如何都可以修改的,用mutable

 

       六、volatile

       这个没有太详细看了。基本上,是通知编译器,这个变量是有可能会变的,无论如何不要基于其不会变化而做优化。

       const volatile int a; 表示本文件不会修改a,但不知道其他文件会不会。

       那我想这种情况下编译器应该不敢将a弄成编译是常数了。但……仍然是!汇编中用的立即数(VC6),是因为我的例子太简单吗?就一个文件。

        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值