当使用#define定义常量时,如#define ASPECT_RATIO 1.653。由于#define是预处理命令,所以ASPECT_RATIO有可能没进入记号表(symbol table)内。因此在有关这个常量出错时,错误提示中没有ASPECT_RATIO记号,于是你将因为追踪它浪费时。解决之道是用const来替换上述的宏(#define): const double AspectRatio = 1.653; 这样AspectRatio会被编译器看到,当然会进入记号表中。
当我们用常量替换#define时,有两种情况需要注意:
1,定义常量指针(const pointers) 有必要将指针(而不是指针所指之物)声明为const,例如:
const char * const authorNaem = "Scott Meyers";
2,定义class的专属常量 #define无法创建一个class的专属常量 所以只能使用const,同时为了确保常量至多有一个实体,用static
class GamePlayer{
private:
static const int NumTurns = 5; //常量声明式 注意只有static整数型class常量才可以in class初值设定
int scores[NumTurns]; //使用该常量
};
注意上面的是NumTurns的声明式而非定义式,通常在头文件中。而有的编译器需要一个定义式,或者需要取它的地址,必须有定义式
const int GamePlayer::NumTurns; //NumTurns的定义 因为在声明时赋值 这里不用赋值
一些旧的编译器不允许static成员在其声明式上获得初值,或者这个class常量不是整型,则需要在定义式时给初值。例如:
class CostEstimate{
private:
static const double FudgeFactor //static class 常量声明 在头文件中
};
const double CostEstimate::FudgeFactor = 1.35 //static class常量定义 在实现文件中
唯一例外是当你在class编译时需要一个class常量,例如上面的GamePlayer::scores的数组声明式时,编译器需要知道数组的大小,而同时编译器不允许static整数型class常量完成in class初值设定,这时可使用"the enum hack",其理论基础是"一个属于枚举类型(enumerated type)的数值可权充ints使用",于是GamePlayer可定义为:
class GamePlayer{
private:
enum {NumTurns = 5}; //"the enum hack" 令NumTurns成为5的一个记号名称
int scores[NumTruns];
};
认识enum hack 即不带实例的无标记enum
1,enum hack的行为像#define 不像const 例如:可以对const取地址 可是不可以对enum 和 #define取地址
2,许多代码使用了enum hack 所以需要认识它
另一个常见的#define误用情况是以它实现宏(macros),宏看起来像函数,但不会带来函数调用的额外开销。上面是一个宏的例子:
//以a 和 b 的较大值调用f
#define CALL_WITH_MAX(a,b) f((a) > (b) ? (a) : (b)) //注要为每个参数加上括号
这样使用有很多的缺点,最好是用inline替代 如下:
template<typename T>
inline void callWithMax(const T& a, const T& b)
{
f(a > b ? a : b);
}
也可以不使用模板函数。
总结:
1,对于单纯常量,最好以const对象或enums替换#define
2,对于形似函数的宏(macros),最好改用inline函数替换#define