小说const
const用法比较复杂,小结下我常见的用法。
- 限定类型修饰符。
- int const a = 1; //int型常量。需要在定义时就初始化。
- int const arr[] = {1 ,2 , 3}; //数组中每一个元素都是常量。但是注意,不能把1中的a和arr[1]当作一样的。比如说可以紧接着这样定义:
int testArr[a]; //正确
int testArr[arr[1]]; //错误
原因:const用于集合时,编译器不会把这个集合放到其符号表中,那么需要为其分配内存。但是虽然为其分配内存,其值却不能在编译阶段使用。 - int const *p; //p是一个指向int型常量的指针。这里的p指针没必要在定义的时候就初始化。不过*p是只读的,就是说不能通过*p来修改其所指向地址的值,但是可以通过其他指针修改。
- int * const p; // p是一个指针常量,指向int型变量。p本身不能改变。不过*p是可读可写的。
- 自然,综合上面两个,就有了int const * const p; //意义不言自明了吧?
- class A; const A a; 简单的用法,跟上面是一样的。不过牵扯到类,就变得复杂了,有些我也搞不明白。
- 转换规则
描述起来费劲,不如看例子。
const int *pa;
int * pb;
pb = pa; //错误,不能直接将指向常量的指针转换为指向非常量的指针。
pa = pb; //正确。
pb = (int *) pa; //可以强制转换。不过转换后就失去了原有的保护机制。这时就可以通过pb修改pa所指向地址的值。 - 作为函数参数
- const修饰函数参数,就是希望函数不修改这个参数的值。对于值传递来说,没必要用const,因为函数即使修改了也是修改的副本,对实参没影响。但是这种拷贝毕竟费时耗内存,所以有了引用。此时又不希望引用被修改,所以可以加上const限定。比如:
void fun( int const & ); - 但是记住,const仅仅只能希望程序不修改参数的值或者参数指向的地址的值,但不能杜绝它那么作。加入const可以让编译器在编译阶段就能检查出不希望的修改行为。但如果你强制修改或通过其他方式,照样是可以达到目的的。比如:
void fun( int const *a){
int *tmp = (int *)a;
*tmp = *tmp +1;
}
- const修饰函数参数,就是希望函数不修改这个参数的值。对于值传递来说,没必要用const,因为函数即使修改了也是修改的副本,对实参没影响。但是这种拷贝毕竟费时耗内存,所以有了引用。此时又不希望引用被修改,所以可以加上const限定。比如:
- 限定函数
主要是限定类的成员函数。如果不希望一个成员函数修改任何一个类的成员数据,比如说这个函数只是打印信息。就可以像下面这样限定:
class A{
void fun(…) const; //不要把const写到最前面了,那意义可就变了。
}
但是,如果某个成员有mutable修饰,那上面的const就不对它保护了,程序可以随便修改。 -
修饰函数返回值
如果像这样:const int fun( );使用,我觉得没有什么意义。因为,系统会将返回值复制到函数外部的临时存储单元中。如果是:const char * fun( ); 那么只能用const char *型变量来保存。const char * rtv = fun( ); -
多文件中共享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 ; - 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?
其实最重要的搞清楚怎么读定义,有一篇很经典的文章,如果看懂,就一切OK了。
[回复]
对于内部数据类型的输入参数,不要将“值传递”的方式改为“const引用传递”。否则既达不到提高效率的目的,又降低了函数的可理解性。例如void fun( int ); 不应该改为void fun( int const & );
[回复]
boluor 回复 于 十二月 5th, 2009 at 17:01
恩,如果是自定义类型的话,const引用传递比较适合。
[回复]
看了你的文章,感觉我真的该多来学习学习。
[回复]
boluor 回复 于 十二月 9th, 2009 at 14:00
^/^,常来常往。
[回复]
你写的真好!学习了!
[回复]
I want to quote your post in my blog. It can?
And you et an account on Twitter?
[回复]
boluor 回复 于 十二月 26th, 2009 at 11:08
It’s my honor, leave a link will be ok ^/^ .
My email : boluor[AT]gmail.com , sorry I have no account on Twitter.
[回复]