Item 02: Prefer consts, enums, and inlines to #defines

Item 02: Prefer consts, enums, and inlines to #defines

尽量以 const,enum,inline 替换 #define


假如有这样的语句:

#define ASPECT_RATIO 1.653

宏定义中的 ASPECT_RATIO 可能从未被编译器看见;也可能编译器处理之前就被预处理器给移走了。那么它很可能不会进入符号表,这样会给编译调试带来很大的困扰,浪费时间。

通常的解决之道是用常量替换宏:

const double AspectRatio = 1.653; 

这样,AspectRatio 肯定会被编译器看到,当然会进入符号表内。

当以常量替换 #defines,有两种情况值得关注:

  • 定义常量指针(constant pointers)时
    由于常量定义通常放在头文件内,因此有必要将指针(而不是指针所指之物)声明为const(常量指针,保证 指针本身不会被修改),如果想要在头文件内定一个 指向常量的指针常量,那么就必须写 const 两次:

    const char* const authorName = "Scott Meyers";
  • 类成员变量
    为了让常量在类中只有一份,必须定义成一个 static 成员:

class GamePlayer {
private:
    static const int NumTurns = 5; // 声明常量
    int scores[NumTurns];          // 使用该常量
    ...
};

上面的 NumTurns 是一个声明而非定义。通常 C++ 要求你对你使用的任何东西提供一个定义式,但是如果它是成员变量且是 static 的且是整数类型(integral type,例如 ints,chars,bools),则需要特殊处理:

  • 只要不取它们的地址,那么就无需提供定义式
  • 但是如果需要取某个成员变量的地址,或者不取地址但是编译器却坚持要看到一个定义式,那就必须另外提供如下定义式:

    const int GamePlayer::Numturns; // NumTurns 的定义,不可以再设初值

    这个语句要放进一个源文件而非头文件。由于 它在声明时已获初值,因此不可以再设初值。

旧的编译器可能不支持上述语法,它们不允许 static 成员在声明的同时获得初值,此外所谓的”类内部设定初值”也只允许对整数常量进行。如果编译器不支持上述语法,那么可以将初值放在定义时设置:

class ConstEstimate {
private:
    static const double FudgeFactor; // static 常量声明
    ...                              //位于 头文件 内 
};

const double                           // static 常量定义
    ConstEstimate::FudgeFactor = 1.35; // 位于 源文件内,不用加 static

有一种例外,就是类编译期间需要用到一个 类成员常量。比如上述的 GamePlayer::scores 数组声明式(编译器要求必须知道数组的大小),而这个时候假如编译器又不允许常量”在类内部设定初值”,这可咋办?可以使用 enum 代替,于是 GamePlayer 可定义如下:

class GamePlayer {
private:
    enum { NumTurns = 5 }; // "The enum hack" -- 令 NumTurns 
                           // 成为 5 的记号名称
    int scores[NumTurns];  // 这样就没问题了.
    ...
};

另一个常见的 #define 错误大家都应该很清楚,经常能遇到,就是 让宏看起来像函数,但是不会导致函数调用带来的开销

# define CALL_WITH_MAX(a, b) f((a) > (b) ? (a) : (b))

诸如此类,即使加上小括号,也可能带来麻烦:

int a = 5, b = 0;
CALL_WITH_MAX(++a, b);      // a 被累加2次
CALL_WITH_MAX(++a, b + 10); // a 被累加1次

看见了吧,a 的增加次数居然取决于 “它被拿来和谁比较”!
这个时候 inline 来了!

template <typename T>
inline coid callWithMax(const T&a, const T& b) {
    f((a) > (b) ? (a) : (b));
}

有了 consts、enums 和 inlines,我们队预处理器的需求降低了,但并非完全消除(例如 #include、#ifdef/#ifndef)。目前不会完全引退,但是能避免使用就避免使用。

请记住

  • 对于单纯常量,最好用 const 对象或 enums 替换 #defines
  • 对于形似函数的宏,最好用 inline 函数替换 #defines
posted @ 2016-07-17 12:37  1202zhyl  阅读(170)  评论(0编辑  收藏  举报