这个条款或许改为“宁可以编译器替换预处理器”比较好
#define ASPECT_RATIO 1.653
替换为:
const double AspectRatio = 1.653
- 处于调试的需要:#define的记号会被预处理器移走,记号名称可能没进入记号表内。因此当#define的宏名称获得一个编译错误时,会引起困惑,浪费大量时间追踪错误。而AspectRatio肯定会被编译器看到
- 更小的代码量:对浮点数而言,使用常量可能比使用#define导致较小量的代码,因为预处理器“盲目地将ASPECT_RATIO替换为1.653”可能导致目标码出现多份1.653
但是,以常量替换#define时要注意:
- 定义常量指针时:由于常量定义式通常被定义在头文件内,因此有必要将指针声明为const。如:
const char* const authorName = "Scott Meyers";
- class专属常量:class专属常量需要声明在class内部,并且被class使用:
对于static修饰的class专属整形常量,如果需要对该常量取地址或编译器坚持要看到一个定义式。那么必须提供类外定义。如果类内声明时提供了初始值,类外定义就不能再设初值。但是某些编译器可能不支持类内初始值,因此需要在类外定义时提供初始值,但是这样就没有像scores成员一样,在类内使用该常量。因此,如果需要使用class专属常量,最好改用“enum hack”
class GamePlayer{ static const int NumTurns = 5; //常量声明式 int scores[NumTurns]; //使用该常量 }; //通常定义出现在头文件中 const int GamePlayer::NumTurns; //NumTurns的定义
正如说明说提到的,编译器可能不支持类内初始值,因此改用"enum hack":
class GamePlayer{
enum {NumTurns = 5};
int scores[NumTurns]; //这就没问题了
};
enum hack的行为比较像#define而不像const。例如取一个const的地址时合法的,但取一个enum的地址就不合法,而取一个#define的地址通常也不合法
以#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次
使用inline函数可以减轻为参数加上括号以及参数被核算多次等问题。同时,inline可以实现一个“类内的private inline函数”,但一般而言宏无法完成此事