关键字const

来源:互联网 发布:weblogic新建域 linux 编辑:程序博客网 时间:2024/04/29 18:52

const意味着"只读"。区别如下代码的功能非常重要,也是老生长叹,如果你还不知道它们的区别,而且已经在程序界摸爬滚打多年,那只能说这是一个悲哀:

const int a;
int const a;
const int *a;
int * const a;
int const * a const;


  (1) 关键字const的作用是为给读你代码的人传达非常有用的信息。例如,在函数的形参前添加const关键字意味着这个参数在函数体内不会被修改,属于"输入参数"。在有多个形参的时候,函数的调用者可以凭借参数前是否有const关键字,清晰的辨别哪些是输入参数,哪些是可能的输出参数。

  (2)合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改,这样可以减少bug的出现。

  const在C++语言中则包含了更丰富的含义,而在C语言中仅意味着:"只能读的普通变量",可以称其为"不能改变的变量"(这个说法似乎很拗口,但却最准确的表达了C语言中const的本质),在编译阶段需要的常数仍然只能以#define宏定义!故在C语言中如下程序是非法的:

const int SIZE = 10;
char a[SIZE]; /* 非法:编译阶段不能用到变量 */

 

、关于const的具体作用
        ——const作用就灵活了,一个表达式中const放置的位置不同,效果可能就不一样了。下面分具体情况分

析(当然,所举的情况并非覆盖全部情况)
        A。const最经常的用法
           1.为了防止传递的函数参数不被修改,在调用函数的形参中用const关键字.
               //Example ->

               int FindNum(const int array[], int num, int conut);//声明函数

               //code...

               int FindNum(const int array[], int num, int count)
               {
                          int i;
                          int flag = 1;

                          for (i = 0; (i < count) && flag; i++)
                          {
                                   if (array[i] == num)
                                   {
                                           flag = 0;
                                           break;
                                   }
                           }
                           return flag;
                }
                //code...
                
           上面这例子中,编译器会把array[]当作常量数据的数组看待。所以,假如你不小心给数组赋值,那么

,编译器就会报错了。因此,当你不需要也不想修改数组的数据时,最好用const把数组定义为常量数组。

           2.const可以用来创建数组常量、指针常量、指向常量的指针等:
             const char ch = 'a';
             const int a[5] = {1, 2, 3, 4, 5};  
             const int *p = a;              //a是一个数组的首地址.p是指向常量的指针
             int * const p = a;             //a是一个数组的首地址.p是指针常量;
             const int * const p = a;    //a是一个数组的首地址。p是指向常量的指针常量

             前两种情况很简单,现在着重分析一下后三种用法,因为这3种情况容易出错,偶就有时候怕用错了

刚脆不用const.

             ——const int *p = a;       //p是指向常量的指针,因此,不可以通过给指针赋值来改变数组

                                                   //中的数据,例如:
                                                   // *p = 10;       /*错误*/
                                                   // *(p + 2) = 1;  /*错误*/

                                                   //假如指向常量指针可以改变值,那么,就等于也改变了数组的数  

                                                   //据了。假如你不理解,偶倒有一个办法让你理解,你就想你和一  

                                                   //个人绑在一起,有可能你移动了位置而他不跟着你移动吗!哈哈

             ——int * const p = a;       //看这表达式,const的位置和第一个不同吧!他们的用法和作用  

                                                    //就完全不一样了。这时候p是指针常量,我们知道,指针是指向  

                                                    //了一个数组的首地址,那么,它的位置就不可以改变了。但是你  

                                                   //现在应该和第一个表达式比较了,现在的数组并不是常量数组,  

                                                   //所以数组的数据是可以改变的,而指针这时候它是不可以移动的  

                                                   //,指向数组第一个数据,所以它可以而且只可以改变数组第一个  

                                                  //数据的值。这一点请别误解,指针常量只是它的地址不可以改变  

                                                  //,并不是它指向的内容一定不可以改变,这一点切记!

                                                  //好啦。假如你又不理解,偶又有一个比较形象的例子来说明:

                                                  //假如有一个固定的人拉着另外一个人的手,注意,固定的人相当  

                                                   //于他是不可以由其他人来替换的。但是他可以拉其他人的手啊,  

                                                  //并不一定规定他必须拉同一个人的手啊。现在你应该可以有个比  

                                                  //较深的印象和理解吧:P

                                                  //下面举几个例子帮助理解:
                                                  //  *p = 2;          /*可以*/
                                                 //  *(p+1) = 10;     /*可以*/
                                                 //  p++;             /*不可以*/

            ——const int * const p = a; //假如前面两种表达式的本质你理解了,这种表达式你来理解根本

                                         //没有问题,const现在有两个,而且一个const的位置是第一种情  

                                         //况的位置,第二个const是第二种情况的位置,所以这表达式的功  

                                         //能就是前两种情况的作用总合。这里不多说!

                                         //下面举几个例子帮助理解:
                                         //  *p = 2;             /*不可以*/
                                         //  *(p + 2) = 10;   /*不可以*/
                                         //  p++;                /*不可以*/

        B。const并不会阻止参数的修改

           之所以把这作为一点来谈,就是因为有一些朋友可能会以为在函数参数中用了const就一定不可以改变

参数,这实际上是错误的理解,因为,它并不阻止参数的修改,下面举个简单的例子来阐述一下;

           #include<stdio.h>
           #include<ctype.h>
          
           void ChangeStr(const char *String);
  
           int main(void)
           {
                    char str[] = "The C programme";

                    Change(str);
                    printf(str);
                    
                    system("Pause");
                    return 0;
            }

            void ChangeStr(const char *String)
            {
                    char *Source = (char *)String;
              
                    while (*Source)
                    {
                               *Source = toupper(*Source);
                               Source++;
                    }
             }

             //end

             上面的程序把字符串中的每个字符都转换成大写字母了。因为*String把地址给了*Source,而

*Source的值的改变编译器并不干涉,可能有的编译器会发出警告之类。上面的程序只是为了说明const并不会阻止

参数的修改,如果象上面程序那样,个人感觉没什么意义,只会让人容易混乱而已。

 

const使用详解
作者:康建东

关于C++中的const关键字的用法非常灵活,而使用const将大大改善程序的健壮性,现将本人的一些体会总结如下,期望对大家有所帮助:

一 const基础

如果const关键字不涉及到指针,我们很好理解,下面是涉及到指针的情况:

int b = 500;const int* a = &b; [1]int const *a = &b;[2]int* const a = &b;[3]const int* const a = &b;[4]

如果你能区分出上述四种情况,那么,恭喜你,你已经迈出了可喜的一步。不知道,也没关系,我们可以参考《Effective c++》Item21上的做法,如果const位于星号的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;如果const位于星号的右侧,const就是修饰指针本身,即指针本身是常量。因此,[1]和[2]的情况相同,都是指针所指向的内容为常量(const放在变量声明符的位置无关),这种情况下不允许对内容进行更改操作,如不能*a = 3 ;[3]为指针本身是常量,而指针所指向的内容不是常量,这种情况下不能对指针本身进行更改操作,如a++是错误的;[4]为指针本身和指向的内容均为常量。
另外const 的一些强大的功能在于它在函数声明中的应用。在一个函数声明中,const 可以修饰函数的返回值,或某个参数;对于成员函数,还可以修饰是整个函数。有如下几种情况,以下会逐渐的说明用法:

A& operator=(const A& a);void fun0(const A* a ); void fun1( ) const;    // fun1( ) 为类成员函数const A fun2( );

二 const的初始化

先看一下const变量初始化的情况
1) 非指针const常量初始化的情况:

A b;const A a = b;

2) 指针(引用)const常量初始化的情况:

A* d = new A();const A* c = d;或者:const A* c = new A();引用:A f;const A& e = f;   // 这样作e只能访问声明为const的函数,而不能访问一般的成员函数;

[思考1]: 以下的这种赋值方法正确吗?
const A* c=new A();
A* e = c;
[思考2]: 以下的这种赋值方法正确吗?
A* const c = new A();
A* b = c;

三 作为参数和返回值的const修饰符

其实,不论是参数还是返回值,道理都是一样的,参数传入时候和函数返回的时候,初始化const变量
1 修饰参数的const,如 void fun0(const A* a ); void fun1(const A& a);
调用函数的时候,用相应的变量初始化const常量,则在函数体中,按照const所修饰的部分进行常量化,如形参为const A* a,则不能对传递进来的指针的内容进行改变,保护了原指针所指向的内容;如形参为const A& a,则不能对传递进来的引用对象进行改变,保护了原对象的属性。
[注意]:参数const通常用于参数为指针或引用的情况;
2 修饰返回值的const,如const A fun2( ); const A* fun3( );
这样声明了返回值后,const按照"修饰原则"进行修饰,起到相应的保护作用。

const Rational operator*(const Rational& lhs, const Rational& rhs){return Rational(lhs.numerator() * rhs.numerator(),lhs.denominator() * rhs.denominator());}

返回值用const修饰可以防止允许这样的操作发生:

Rational a,b;Radional c;(a*b) = c;

一般用const修饰返回值为对象本身(非引用和指针)的情况多用于二目操作符重载函数并产生新对象的时候。
[总结] 一般情况下,函数的返回值为某个对象时,如果将其声明为const时,多用于操作符的重载。通常,不建议用const修饰函数的返回值类型为某个对象或对某个对象引用的情况。
原因如下:
如果返回值为某个对象为const(const A test = A 实例)或某个对象的引用为const(const A& test = A实例) ,则返回值具有const属性,则返回实例只能访问类A中的公有(保护)数据成员和const成员函数,并且不允许对其进行赋值操作,这在一般情况下很少用到。


[思考3]: 这样定义赋值操作符重载函数可以吗?
const A& operator=(const A& a);

四 类成员函数中const的使用

一般放在函数体后,形如:void fun() const;
如果一个成员函数的不会修改数据成员,那么最好将其声明为const,因为const成员函数中不允许对数据成员进行修改,如果修改,编译器将报错,这大大提高了程序的健壮性。

五 使用const的一些建议

1 要大胆的使用const,这将给你带来无尽的益处,但前提是你必须搞清楚原委;
2 要避免最一般的赋值操作错误,如将const变量赋值,具体可见思考题;
3 在参数中使用const应该使用引用或指针,而不是一般的对象实例,原因同上;
4 const在成员函数中的三种用法(参数、返回值、函数)要很好的使用;
5 不要轻易的将函数的返回值类型定为const;
6除了重载操作符外一般不要将返回值类型定为对某个对象的const引用;

原创粉丝点击