新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     >>计算机科学论坛<<     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 本版讨论高级C/C++编程、代码重构(Refactoring)、极限编程(XP)、泛型编程等话题
    [返回] 计算机科学论坛计算机技术与应用『 C/C++编程思想 』 → const传奇 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 9735 个阅读者浏览上一篇主题  刷新本主题   平板显示贴子 浏览下一篇主题
     * 贴子主题: const传奇 举报  打印  推荐  IE收藏夹 
       本主题类别: C/C++编程思想    
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客楼主
    发贴心情 const传奇

    简介

    当我自己写程序需要用到const的时候,或者是读别人的代码碰到const的时候,我常常会停下来想一会儿。许多程序员从来不用const,理由是即使没用const他们也这么过来了。本文仅对const的用法稍作探讨,希望能够对提高软件的源代码质量有所帮助。

    常变量

    变量用const修饰,其值不得被改变。任何改变此变量的代码都会产生编译错误。Const加在数据类型前后均可。

    例如:

    void main(void)

    {

        const int i = 10;    //i,j都用作常变量

        int const j = 20;

        i = 15;            //错误,常变量不能改变

        j = 25;            //错误,常变量不能改变

    }

    常指针

    Const跟指针一起使用的时候有两种方法。

    const可用来限制指针不可变。也就是说指针指向的内存地址不可变,但可以随意改变该地址指向的内存的内容。

    int main(void)

    {

           int i = 10;

           int *const j = &i;   //常指针, 指向int型变量

           (*j)++;                //可以改变变量的内容

           j++;                    //错误,不能改变常指针指向的内存地址

    }

    const也可用来限制指针指向的内存不可变,但指针指向的内存地址可变。

    int main(void)

    {

           int i = 20;

           const int *j = &i;   //指针,指向int型常量

           //也可以写成int const *j = &i;

           j++;                      //指针指向的内存地址可变

           (*j)++;                  //错误,不能改变内存内容

    }

    看完上面的两个例子,是不是糊涂了?告诉你一个诀窍,在第一个例子中,const用来修饰指针j,j不可变(也就是指向int变量的常指针);第二个例子中,const用来修饰*j,*j不可变(也就是指向int常量的指针)。

    这两种方式可以组合起来使用,使指针和内存内容都不可变。

    int main(void)

    {

           int i = 10;

           const int *const j = &i;  //指向int常量的常指针

           j++;                   //错误,不能改变指针指向的地址

           (*j)++;          //错误,不能改变常量的值

    }

    Const和引用

    引用实际上就是变量的别名,这里有几条规则:

    声明变量时必须初始化

    一经初始化,引用不能在指向其它变量。

    任何对引用的改变都将改变原变量。

    引用和变量本身指向同一内存地址。

    下面的例子演示了以上的规则:

    void main(void)

    {

        int i = 10;                    //i和j是int型变量

        int j = 20;        

        int &r = i;                    //r 是变量i的引用

        int &s;                        //错误,声明引用时必须初始化

        i = 15;                        //i 和 r 都等于15

        i++;                        //i 和 r都等于16

        r = 18;                        //i 和r 都等于18

        printf("Address of i=%u, Address of r=%u",&i,&r);    //内存地址相同

        r = j;                        //i 和 r都等于20,但r不是j的引用

        r++;                        //i 和 r 都等于21, j 仍等于20

    }

    用const修饰引用,使应用不可修改,但这并不耽误引用反映任何对变量的修改。Const加在数据类型前后均可。

    例如:

    void main(void)

    {

        int i = 10;

        int j = 100;

        const int &r = i;

        int const &s = j;

        r = 20;          //错,不能改变内容

        s = 50;          //错,不能改变内容

        i = 15;          // i和r 都等于15

        j = 25;          // j和s 都等于25

    }

    Const和成员函数

    声明成员函数时,末尾加const修饰,表示在成员函数内不得改变该对象的任何数据。这种模式常被用来表示对象数据只读的访问模式。例如:

    class MyClass

    {

        char *str ="Hello, World";

        MyClass()

        {

            //void constructor

        }

        

        ~MyClass()

        {

            //destructor

        }

        char ValueAt(int pos) const    //const method is an accessor method

        {

            if(pos >= 12)

                   return 0;

                  *str = 'M';          //错误,不得修改该对象

            return str[pos];          //return the value at position pos

        }

    }

    Const和重载

    重载函数的时候也可以使用const,考虑下面的代码:

    class MyClass

    {

        char *str ="Hello, World";

        MyClass()

        {

            //void constructor

        }

        

        ~MyClass()

        {

            //destructor

        }

        char ValueAt(int pos) const    //const method is an accessor method

        {

            if(pos >= 12)

                   return 0;

            return str[pos];    //return the value at position pos

        }

        

        char& ValueAt(int pos)        //通过返回引用设置内存内容

        {

            if(pos >= 12)

                   return NULL;

            return str[pos];

        }

    }

    在上面的例子中,ValueAt是被重载的。Const实际上是函数参数的一部分,在第一个成员函数中它限制这个函数不能改变对象的数据,而第二个则没有。这个例子只是用来说明const可以用来重载函数,没有什么实用意义。

    实际上我们需要一个新版本的GetValue。如果GetValue被用在operator=的右边,它就会充当一个变量;如果GetValue被用作一元操作符,那么返回的引用可以被修改。这种用法常用来重载操作符。String类的operator[]是个很好的例子。(这一段译得很烂,原文如下:In reality due to the beauty of references just the second definition of GetValue is actually required. If the GetValue method is used on the the right side of an = operator then it will act as an accessor, while if it is used as an l-value (left hand side value) then the returned reference will be modified and the method will be used as setter. This is frequently done when overloading operators. The [] operator in String classes is a good example.)

    class MyClass

    {

        char *str ="Hello, World";

        MyClass()

        {

            //void constructor

        }

        

        ~MyClass()

        {

            //destructor

        }

        char& operator[](int pos)        //通过返回引用可用来更改内存内容

        {

            if(pos >= 12)

                   return NULL;

            return str[pos];

        }

    }

    void main(void)

    {

        MyClass m;

        char ch = m[0];        //ch 等于 'H'

        m[0] = 'M';        //m的成员str变成:Mello, World

    }

    Const的担心

    C/C++中,数据传递给函数的方式默认的是值传递,也就是说当参数传递给函数时会产生一个该参数的拷贝,这样该函数内任何对该参数的改变都不会扩展到此函数以外。每次调用该函数都会产生一个拷贝,效率不高,尤其是函数调用的次数很高的时候。

    例如:

    class MyClass

    {

    public:

        int x;    

        char ValueAt(int pos) const    //const method is an accessor method

        {

            if(pos >= 12)

                   return 0;

            return str[pos];    //return the value at position pos

        }

        MyClass()

        {

            //void constructor

        }

        ~MyClass()

        {

            //destructor

        }

        MyFunc(int y)    //值传递

        {

            y = 20;

            x = y;    //x 和 y 都等于 20.

        }

    }

    void main(void)

    {

        MyClass m;

        int z = 10;

        m.MyFunc(z);

        printf("z=%d, MyClass.x=%d",z,m.x);    //z 不变, x 等于20.

    }

    通过上面的例子可以看出,z没有发生变化,因为MyFunc()操作的是z的拷贝。为了提高效率,我们可以在传递参数的时候,不采用值传递的方式,而采用引用传递。这样传递给函数的是该参数的引用,而不再是该参数的拷贝。然而问题是如果在函数内部改变了参数,这种改变会扩展到函数的外部,有可能会导致错误。在参数前加const修饰保证该参数在函数内部不会被改变。

    class MyClass

    {

    public:

        int x;

        MyClass()

        {

            //void constructor

        }

        ~MyClass()

        {

            //destructor

        }

        int MyFunc(const int& y)    //引用传递, 没有任何拷贝

        {

            y =20;    //错误,不能修改常变量

            x = y    

        }

    }

    void main(void)

    {

        MyClass m;

        int z = 10;

        m.MyFunc(z);

        printf("z=%d, MyClass.x=%d",z,m.x);    //z不变, x等于10.

    }

    如此,const通过这种简单安全机制使你写不出那种说不定是什么时候就会掉过头来咬你一口的代码。你应该尽可能的使用const引用,通过声明你的函数参数为常变量(任何可能的地方)或者定义那种const method,你就可以非常有效确立这样一种概念:本成员函数不会改变任何函数参数,或者不会改变任何该对象的数据。别的程序员在使用你提供的成员函数的时候,不会担心他们的数据被改得一塌糊涂


       收藏   分享  
    顶(0)
      




    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2006/10/23 15:32:00
     
     GoogleAdSense
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 C/C++编程思想 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/5/12 23:42:17

    本主题贴数2,分页: [1]

     *树形目录 (最近20个回帖) 顶端 
    主题:  const传奇(7853字) - 卷积内核,2006年10月23日
        回复:  const char * const foo(char const * const str) co..(2040字) - 卷积内核,2006年10月24日

    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    93.750ms