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