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

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

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

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

    尽量用const和inline而不用#define

    这个条款最好称为:“尽量用编译器而不用预处理”,因为#define经常被认为好象不是语言本身的一部分。这是问题之一。再看下面的语句:

    #define ASPECT_RATIO 1.653

    编译器会永远也看不到ASPECT_RATIO这个符号名,因为在源码进入编译器之前,它会被预处理程序去掉,于是ASPECT_RATIO不会加入到符号列表中。如果涉及到这个常量的代码在编译时报错,就会很令人费解,因为报错信息指的是1.653,而不是ASPECT_RATIO。如果ASPECT_RATIO不是在你自己写的头文件中定义的,你就会奇怪1.653是从哪里来的,甚至会花时间跟踪下去。这个问题也会出现在符号调试器中,因为同样地,你所写的符号名不会出现在符号列表中。
    解决这个问题的方案很简单:不用预处理宏,定义一个常量:

    const double ASPECT_RATIO = 1.653;

    这种方法很有效。但有两个特殊情况要注意。
    首先,定义指针常量时会有点不同。因为常量定义一般是放在头文件中(许多源文件会包含它),除了指针所指的类型要定义成const外,重要的是指针也经常要定义成const。例如,要在头文件中定义一个基于char*的字符串常量,你要写两次const:

    const char * const authorName = "Scott Meyers";

    关于const的含义和用法,特别是和指针相关联的问题,参见条款21。

    另外,定义某个类(class)的常量一般也很方便,只有一点点不同。要把常量限制在类中,首先要使它成为类的成员;为了保证常量最多只有一份拷贝,还要把它定义为静态成员:
        

    class GamePlayer {
    private:
     static const int NUM_TURNS = 5; // constant eclaration
     int scores[NUM_TURNS];  // use of constant
     ...
    };

    还有一点,正如你看到的,上面的语句是NUM_TURNS的声明,而不是定义,所以你还必须在类的实现代码文件中定义类的静态成员:

    const int GamePlayer::NUM_TURNS; // mandatory definition;
      // goes in class impl.file

    你不必过于担心这种小事。如果你忘了定义,链接器会提醒你。

    旧一点的编译器会不接受这种语法,因为它认为类的静态成员在声明时定义初始值是非法的;而且,类内只允许初始化整数类型(如:int, bool, char 等),还只能是常量。
    在上面的语法不能使用的情况下,可以在定义时赋初值:


    class EngineeringConstants { // this goes in the class
    private:  // header file
     static const double FUDGE_FACTOR;
     ...
    };
     // this goes in the class implementation file
     const double EngineeringConstants::FUDGE_FACTOR = 1.35;

    大多数情况下你只要做这么多。唯一例外的是当你的类在编译时需要用到这个类的常量的情况,例如上面GamePlayer::scores数组的声明(编译过程中编译器一定要知道数组的大小)。所以,为了弥补那些(不正确地)禁止类内进行整型类常量初始化的编译器的不足,可以采用称之为“借用enum”的方法来解决。这种技术很好地利用了当需要int类型时可以使用枚举类型的原则,所以GamePlayer也可以象这样来定义:


    class GamePlayer {
    private:
     enum { NUM_TURNS = 5 } // "the enum hack" — makes
     // NUM_TURNS a symbolic name
     // for 5
     int scores[NUM_TURNS];// fine
    };

    除非你正在用老的编译器(即写于1995年之前),你不必借用enum。当然,知道有这种方法还是值得的,因为这种可以追溯到很久以前的时代的代码可是不常见的哟。

    回到预处理的话题上来。另一个普遍的#define指令的用法是用它来实现那些看起来象函数而又不会导致函数调用的宏。典型的例子是计算两个对象的最大值:


    #define max(a,b) ((a) > (b) ? (a) : (b))

    这个语句有很多缺陷,光想想都让人头疼,甚至比在高峰时间到高速公路去开车还让人痛苦。
    无论什么时候你写了象这样的宏,你必须记住在写宏体时对每个参数都要加上括号;否则,别人调用你的宏时如果用了表达式就会造成很大的麻烦。但是即使你象这样做了,还会有象下面这样奇怪的事发生:

    int a = 5, b = 0;
    max(++a, b);// a 的值增加了2次
    max(++a, b+10); // a 的值只增加了1次

    这种情况下,max内部发生些什么取决于它比较的是什么值!
    幸运的是你不必再忍受这样愚笨的语句了。你可以用普通函数实现宏的效率,再加上可预计的行为和类型安全,这就是内联函数(见条款33):


    inline int max(int a, int b) { return a > b ? a : b; }
    不过这和上面的宏不大一样,因为这个版本的max只能处理int类型。但模板可以很轻巧地解决这个问题:


    template<class T>
    inline const T& max(const T& a, const T& b)
    { return a > b ? a : b; }

    这个模板产生了一整套函数,每个函数拿两个可以转换成同种类型的对象进行比较然后返回较大的(常量)对象的引用。因为不知道T的类型,返回时传递引用可以提高效率。

    顺便说一句,在你打算用模板写象max这样有用的通用函数时,先检查一下标准库,看看他们是不是已经存在。比如说上面说的max,你会惊喜地发现你可以后人乘凉:max是C++标准库的一部分。
    有了const和inline,你对预处理的需要减少了,但也不能完全没有它。抛弃#include的日子还很远,#ifdef/#ifndef在控制编译的过程中还扮演重要角色。预处理还不能退休,但你一定要计划给它经常放长假。


       收藏   分享  
    顶(0)
      




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

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2006/6/28 16:03:00
     
     猪头菜鸟 帅哥哟,离线,有人找我吗?
      
      
      等级:大一新生
      文章:1
      积分:65
      门派:XML.ORG.CN
      注册:2006/8/3

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给猪头菜鸟发送一个短消息 把猪头菜鸟加入好友 查看猪头菜鸟的个人资料 搜索猪头菜鸟在『 C/C++编程思想 』的所有贴子 引用回复这个贴子 回复这个贴子 查看猪头菜鸟的博客2
    发贴心情 
    谢谢!!
    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2006/8/4 11:05:00
     
     quicker2008 帅哥哟,离线,有人找我吗?
      
      
      等级:大一新生
      文章:2
      积分:64
      门派:XML.ORG.CN
      注册:2006/10/12

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给quicker2008发送一个短消息 把quicker2008加入好友 查看quicker2008的个人资料 搜索quicker2008在『 C/C++编程思想 』的所有贴子 引用回复这个贴子 回复这个贴子 查看quicker2008的博客3
    发贴心情 
    以下是引用卷积内核在2006-6-28 16:03:00的发言:
    尽量用const和inline而不用#define

    这个条款最好称为:“尽量用编译器而不用预处理”



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

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

    管理选项修改tag | 锁定 | 解锁 | 提升 | 删除 | 移动 | 固顶 | 总固顶 | 奖励 | 惩罚 | 发布公告
    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    62.500ms