小说const

const用法比较复杂,小结下我常见的用法。

  1. 限定类型修饰符。
    1. int const a = 1; //int型常量。需要在定义时就初始化。
    2.   

    3. int const arr[] = {1 ,2 , 3}; //数组中每一个元素都是常量。但是注意,不能把1中的a和arr[1]当作一样的。比如说可以紧接着这样定义:
      int testArr[a]; //正确
      int testArr[arr[1]]; //错误
      原因:const用于集合时,编译器不会把这个集合放到其符号表中,那么需要为其分配内存。但是虽然为其分配内存,其值却不能在编译阶段使用。
    4.   

    5. int const *p; //p是一个指向int型常量的指针。这里的p指针没必要在定义的时候就初始化。不过*p是只读的,就是说不能通过*p来修改其所指向地址的值,但是可以通过其他指针修改。
    6.   

    7. int * const p; // p是一个指针常量,指向int型变量。p本身不能改变。不过*p是可读可写的。
    8.   

    9. 自然,综合上面两个,就有了int const * const p; //意义不言自明了吧?
    10.   

    11. class A; const A a; 简单的用法,跟上面是一样的。不过牵扯到类,就变得复杂了,有些我也搞不明白。
  2. 转换规则
      描述起来费劲,不如看例子。
      const int *pa;
      int * pb;
      pb = pa; //错误,不能直接将指向常量的指针转换为指向非常量的指针。
      pa = pb; //正确。
      pb = (int *) pa; //可以强制转换。不过转换后就失去了原有的保护机制。这时就可以通过pb修改pa所指向地址的值。
  3.  

  4. 作为函数参数
        
    1. const修饰函数参数,就是希望函数不修改这个参数的值。对于值传递来说,没必要用const,因为函数即使修改了也是修改的副本,对实参没影响。但是这种拷贝毕竟费时耗内存,所以有了引用。此时又不希望引用被修改,所以可以加上const限定。比如:
      void fun( int const & );
    2.   

    3. 但是记住,const仅仅只能希望程序不修改参数的值或者参数指向的地址的值,但不能杜绝它那么作。加入const可以让编译器在编译阶段就能检查出不希望的修改行为。但如果你强制修改或通过其他方式,照样是可以达到目的的。比如:
      void fun( int const *a){
      int *tmp = (int *)a;
      *tmp = *tmp +1;
      }
  5.  

  6. 限定函数
      主要是限定类的成员函数。如果不希望一个成员函数修改任何一个类的成员数据,比如说这个函数只是打印信息。就可以像下面这样限定:
    class A{
    void fun(…) const; //不要把const写到最前面了,那意义可就变了。
    }
      但是,如果某个成员有mutable修饰,那上面的const就不对它保护了,程序可以随便修改。
  7.  

  8. 修饰函数返回值
      如果像这样:const int fun( );使用,我觉得没有什么意义。因为,系统会将返回值复制到函数外部的临时存储单元中。如果是:const char * fun( ); 那么只能用const char *型变量来保存。const char * rtv = fun( );
  9.  

  10. 多文件中共享const常量
      在C中定义时,如果是: int Max = 100 ; 默认的linkage就是extern,此时在其他文件中通过声明extern int Max ; 就可以使用Max 了。有时候需要在多个源文件中共享某个常量,此时注意了。在C++中,const定义默认具有 internal linkage,如果你定义int const Max = 100 ; 希望其他文件通过声明: extern int const Max ;来使用Max,那就会编译错误,提示找不到Max。此时需要显示的声明为Max为extern,即extern int const Max = 100 ;
  11.  

  12. const其他
      const比#define要好得多的多。#define是在预处理时展开,定义的符号在编译完成之后,就不存在了,原来的地方全部成了立即数。const定义的常量在运行期间也是存在的,在编译阶段有可能加入符号表,方便查询,所以编译速度也不是大问题。由上也可推出,const会在某些场合比define少些内存分配。比如说:const str[] = “hello”; 如果程序中用到了多次str,那么str只需要一次内存分配,之后使用只要给出地址就行。而define:#define str “hello”; 将多次出现的地方全部替换成了立即数,那么每次使用时都需要为之分配内存,也就是说内存中会存在str的多个拷贝。

———————————————————————————————————

  上面的代码可能有让你不舒服的地方,尤其 int const * p ; 而不是写作 const int *p ; 在说明我为什么这么写(下一篇文章)之前,问个问题,如果你能很清晰地回答正确,就没必要继续看了。
  参考:Dan Saks写的《const T vs T const》。
  [问题]
typedef void *VP;
const VP vectorTable[] = { … …};
跟下面的是不是等价的?
const void *vectorTable[] = { …… };

5 Comments are ready?

  1. felix021 said on: 2009年12月5日 11:20

    其实最重要的搞清楚怎么读定义,有一篇很经典的文章,如果看懂,就一切OK了。

    [回复]

  2. candy said on: 2009年12月5日 13:59

    对于内部数据类型的输入参数,不要将“值传递”的方式改为“const引用传递”。否则既达不到提高效率的目的,又降低了函数的可理解性。例如void fun( int ); 不应该改为void fun( int const & );

    [回复]

    boluor 回复  于   

    恩,如果是自定义类型的话,const引用传递比较适合。

    [回复]

  3. GEZ鸽子 said on: 2009年12月9日 10:30

    看了你的文章,感觉我真的该多来学习学习。

    [回复]

    boluor 回复  于   

    ^/^,常来常往。

    [回复]

  4. Felicia said on: 2009年12月11日 00:18

    你写的真好!学习了!

    [回复]

  5. Phoenix_Ukraine said on: 2009年12月26日 01:42

    I want to quote your post in my blog. It can?
    And you et an account on Twitter?

    [回复]

    boluor 回复  于   

    It’s my honor, leave a link will be ok ^/^ .

    My email : boluor[AT]gmail.com , sorry I have no account on Twitter.

    [回复]

Post a Comment

Your email is never published nor shared. Required fields are marked *

*

*

click to changeSecurity Code