a我考网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 108|回复: 1

[C++] c++语言中const关键字的详细使用解释

[复制链接]
发表于 2012-7-31 21:56:58 | 显示全部楼层 |阅读模式
C++中的const关键字的用法非常灵活,而使用const将大大改善程序的健壮性,本人根据各方面查到的资料进行总结如下,期望对朋友们有所帮助。
& M& A+ w! R2 F: ]! _  Const 是C++中常用的类型修饰符,常类型是指使用类型修饰符const说明的类型,常类型的变量或对象的值是不能被更新的。) ~8 K/ N9 A; o! Q3 B7 ~1 L
  一、Const作用
) @& D7 p" |7 A' d  如下表所示:& e" Y. I* K. c" L
  No.
( C. u6 l2 L; K- I  作用
& I- i. `% ?9 q% Z$ P7 W7 r  说明
6 p& t1 _/ R5 q' j$ |  参考代码
+ E& ^7 C, D0 m  1* s. G4 Q: R$ }) H/ a7 x
  可以定义const常量
( E& v$ d1 U& ^# \- \0 b  const int Max = 100;& F' \8 F- }+ m. X+ B
  28 _6 K+ N9 |# E( O3 J7 p3 J6 E
  便于进行类型检查+ P, r" I: v" P4 Z
  const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换时可能会产生意料不到的错误
: u4 Y4 S+ P( H9 y9 [  void f(const int i) { .........}
1 I9 ?* Q+ _" c7 g7 _0 v! ^  //对传入的参数进行类型检查,不匹配进行提示1 d$ \; b6 F* k1 y
  3+ v5 N0 X6 l2 r
  可以保护被修饰的东西
8 Q  `6 P& w' o0 j5 P' @  防止意外的修改,增强程序的健壮性。1 T4 m( J8 t1 A- L% g! e
  void f(const int i) { i=10;//error! }3 c' E' U1 ?- u# y
  //如果在函数体内修改了i,编译器就会报错$ X, M  ]; d/ ~9 w
  4
6 x: d0 t- r; q0 l  e  可以很方便地进行参数的调整和修改% K% P# f2 [/ U4 v
  同宏定义一样,可以做到不变则已,一变都变
! P- ?/ L9 W6 [  y5 e$ ^2 Z  5; [2 p3 M! z1 U! ^3 J0 T! c
  为函数重载提供了一个参考
+ E! L/ ^9 l4 v  ?  class A
1 H# S( q4 Z, k+ V  {
, e( E, `, s* j+ S% e  |& T* _  ......( }: W! S+ R: t6 q
  void f(int i)       {......} //一个函数
3 v9 U9 e% r; G  m) o) v# S  void f(int i) const {......} //上一个函数的重载
, g' E0 }7 L$ M# D: f9 y6 h  ......
8 u1 a9 P& y8 }* `* \& J3 M; C  };
) C( z. {4 U* _1 C  6( [2 d1 e+ r+ k- D
  可以节省空间,避免不必要的内存分配9 s; ~2 w$ z. L4 _( \
  const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝
6 Z+ `# R& [2 `  #define PI 3.14159         //常量宏
6 F+ c, T5 g' L3 Y7 W* m7 s* q# I( t  const doulbe  Pi=3.14159;  //此时并未将Pi放入ROM中4 I( u9 j+ B. L& ^' u' w
  ......
0 ^$ W* B0 n4 n0 m  double i=Pi;   //此时为Pi分配内存,以后不再分配!" N; V% B# v. d* `% j5 [
  double I=PI;  //编译期间进行宏替换,分配内存: l5 P( V5 \  ]/ |4 S% p) F
  double j=Pi;  //没有内存分配- f4 S+ D$ I5 \5 O' \7 N& b
  double J=PI;  //再进行宏替换,又一次分配内存!
8 h( G- O7 t1 `' k( w  7
9 x, d) H8 E' B1 r0 y* M  提高了效率
  w& u9 |9 {+ o  p  编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高!0 t% _2 H% y3 y- c
  二、Const的使用
7 g7 [( l- n5 R+ a( I- G6 i/ J3 f  1、定义常量/ A( Z' w9 A$ F0 U. J/ y
  (1)const修饰变量,以下两种定义形式在本质上是一样的。它的含义是:const修饰的类型为TYPE的变量value是不可变的。- Z8 R' a, @$ |! X
  TYPE const ValueName = value;
; y9 s5 q" ?- x& ?0 A7 G  const TYPE ValueName = value;& s, `' [* R  h% k4 V
  (2)将const改为外部连接,作用于扩大至全局,编译时会分配内存,并且可以不进行初始化,仅仅作为声明,编译器认为在程序其他地方进行了定义.7 k1 s0 f1 t# W: @
  extend const int ValueName = value;
5 |  P4 L/ Q0 t# ?  2、指针使用CONST/ N& \: N( V& ^: r3 i8 A; {/ R' \
  (1)指针本身是常量不可变
& Z& p2 }4 \8 p  F0 n" e* \- U  (char*) const pContent;
  `! r- }! L0 i$ `4 I' [  const (char*) pContent;6 _( g4 g; j- h1 ?  D0 n( S
  (2)指针所指向的内容是常量不可变5 Y( |1 }2 t/ x+ q% R4 A; y
  const (char) *pContent;- e+ m1 s0 o: z
  (char) const *pContent;
% u. s* ~5 Z' h% [( N  (3)两者都不可变( c) C* ]4 a" P; `& x% _3 o
  const char* const pContent;
! F: ?% Q* c0 ?- S$ _0 z  (4)还有其中区别方法,沿着*号划一条线:
6 i, L: T+ X% J0 E  如果const位于*的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;9 c) G5 |  G! W& f
  如果const位于*的右侧,const就是修饰指针本身,即指针本身是常量。
回复

使用道具 举报

 楼主| 发表于 2012-7-31 21:56:59 | 显示全部楼层

c++语言中const关键字的详细使用解释

  3、函数中使用CONST
/ S3 Z# ^- y$ v& e7 _  (1)const修饰函数参数
" r2 V) f7 t' M4 m( p  a.传递过来的参数在函数内不可以改变(无意义,因为Var本身就是形参)
" M/ |3 z" c$ {3 y' M  void function(const int Var);1 m* Z+ f2 n: t0 C1 P# X
  b.参数指针所指内容为常量不可变
% s0 v' R* a$ Q$ ?3 J- S1 j1 C  void function(const char* Var);* G" \4 P2 D( I7 b8 x6 H
  c.参数指针本身为常量不可变(也无意义,因为char* Var也是形参)
0 i8 ]) `! ]* h  h8 f/ K  void function(char* const Var);! X2 Z7 K; u" e& M4 q
  d.参数为引用,为了增加效率同时防止修改。修饰引用参数时:
( T( ]' u1 I4 r6 s# e0 ?( I8 b  void function(const Class& Var); //引用参数在函数内不可以改变9 y5 `, g2 {; [+ j! C9 Q
  void function(const TYPE& Var); //引用参数在函数内为常量不可变& Y: M8 n5 k# d- T4 f1 H0 K
  这样的一个const引用传递和最普通的函数按值传递的效果是一模一样的,他禁止对引用的对象的一切修改,唯一不同的是按值传递会先建立一个类对象的副本, 然后传递过去,而它直接传递地址,所以这种传递比按值传递更有效.另外只有引用的const传递可以传递一个临时对象,因为临时对象都是const属性, 且是不可见的,他短时间存在一个局部域中,所以不能使用指针,只有引用的const传递能够捕捉到这个家伙
& R4 p0 F& @" a- l  (2)const 修饰函数返回值* m- ^$ a( W% X) o; T
  const修饰函数返回值其实用的并不是很多,它的含义和const修饰普通变量以及指针的含义基本相同。
) |0 C( p) f. d% G. [  a.const int fun1() //这个其实无意义,因为参数返回本身就是赋值。
: r. |# N, O, v  j  b. const int * fun2() //调用时 const int *pValue = fun2();
( h/ [; U2 V! t" ~! ]0 M  //我们可以把fun2()看作成一个变量,即指针内容不可变。, `5 p3 S0 \4 n* t; \4 [, M
  c.int* const fun3()   //调用时 int * const pValue = fun2();- k  @+ @2 V% m- p
  //我们可以把fun2()看作成一个变量,即指针本身不可变。+ [9 x2 }( k0 H! {% Q( n  X/ e" ~) V
  一般情况下,函数的返回值为某个对象时,如果将其声明为const时,多用于操作符的重载。通常,不建议用const修饰函数的返回值类型为某个对象或对某个对象引用的情况。原因如下:如果返回值为某个对象为const(const A test = A 实例)或某个对象的引用为const(const A& test = A实例),则返回值具有const属性,则返回实例只能访问类A中的公有(保护)数据成员和const成员函数,并且不允许对其进行赋值操作,这在一般情况下很少用到。- ]( k! J& |! J. M  D/ U8 E
  4、类相关CONST( M# y& m) e, N5 c  D
  (1)const修饰成员变量5 ?4 m7 }/ t' y5 X  ]  E" ?
  const修饰类的成员函数,表示成员常量,不能被修改,同时它只能在初始化列表中赋值。
6 c! Y" T) P* p# M; G  class A
$ {8 V2 i# o& u  {
" |  f2 G9 T1 K5 d2 ?6 `( \  …! T* S2 l! o0 c; d& |: U/ @4 k  N
  const int nValue;         //成员常量不能被修改$ V, _& h6 y2 @* }% ~, `$ V' b
  …5 J. o% M7 s' C% L/ M9 u8 |
  A(int x): nValue(x) { } ; //只能在初始化列表中赋值8 W9 N7 f, F! d3 {" D
  }
- J: b( f9 o% A3 m  (2)const修饰成员函数
3 P% Z# L4 _$ s  const修饰类的成员函数,则该成员函数不能修改类中任何非const成员函数。一般写在函数的最后来修饰。0 _& G( T- G) i/ a) q2 o
  class A  i0 i! J5 [, d2 d
  {: |% Y" }% g: C1 }: Q
  …8 P2 G, W& x3 Z/ V
  void function()const; //常成员函数, 它不改变对象的成员变量.
+ M+ v# ^) V- c/ U" @* x! \9 S  //也不能调用类中任何非const成员函数。& }  o6 O4 t) j" n# \, T
  }7 F& z, E8 N8 i1 X8 x
  对于const类对象/指针/引用,只能调用类的const成员函数,因此,const修饰成员函数的最重要作用就是限制对于const对象的使用。</p>a. const成员函数不被允许修改它所在对象的任何一个数据成员。
1 |6 B& U( W, U0 M# o- Z  b. const成员函数能够访问对象的const成员,而其他成员函数不可以。0 o5 m  {* f1 y, G/ j) u- X; Z5 }
  (3)const修饰类对象/对象指针/对象引用
# e. o# g7 b& V0 ^  ·             const修饰类对象表示该对象为常量对象,其中的任何成员都不能被修改。对于对象指针和对象引用也是一样。
3 M) F+ ~* Q# [  ·             const修饰的对象,该对象的任何非const成员函数都不能被调用,因为任何非const成员函数会有修改成员变量的企图。
) R+ W& S9 ^& f2 z6 Z: v7 A  例如:9 O- [" H( O' H
  class AAA
- h9 o1 {# ^' H; T7 t0 c9 L  {6 m  m; B8 F% E/ w1 u7 t  Z# ~
  void func1();
* @, A& z0 C+ p* ]  void func2() const;7 X0 T9 |& i- Q9 b
  }- D+ }& Z# z1 ]  [0 U4 ^
  const AAA aObj;- d0 @! O9 b# P" W1 Y
  aObj.func1(); ×
1 d, \3 R- }: t4 F  aObj.func2(); 正确
  M  A, B* g6 G6 e  const AAA* aObj = new AAA();) M5 u  W1 D4 a; B$ }
  aObj-> func1(); ×2 N4 Z5 |% D( ?5 N; A8 ?
  aObj-> func2(); 正确. P( f+ k1 x3 b8 p& |4 @& z
  三、将Const类型转化为非Const类型的方法# S# V' Z: t: J2 g% u8 J
  采用const_cast 进行转换。
7 X( K. d% k' w' s4 b- v  l  用法:const_cast   (expression)$ ?+ q4 {; Y! K  @: {& Z
  该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, type_id和expression的类型是一样的。7 e  n( E9 v, p1 M/ Q# k+ n9 Y
  ·             常量指针被转化成非常量指针,并且仍然指向原来的对象;: r2 g! e" \  V1 M0 M
  ·             常量引用被转换成非常量引用,并且仍然指向原来的对象;' d& X8 q% n6 [9 j3 c
  ·             常量对象被转换成非常量对象
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Woexam.Com ( 湘ICP备18023104号 )

GMT+8, 2024-5-4 16:03 , Processed in 0.203597 second(s), 23 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表