这里说的意思其实相当于,宁可以用编译器来替换预处理器
因为使用预处理器可能使得被处理过的东西无法进入符号表,例如 #define MAXLEN 16 这里的MAXLEN并没有进入符号表,这样有编译错误出现的时候,提示的都是16而并不是MAXLEN,这样就会带来很多的错误。
对于上面的那个式子,可以尝试的使用用一个常量去替换上面的宏:const int MAXLEN = 16
注意,常量的定义式往往被放在头文件中
应该要注意到的一点:class专属常量,为了将作用域限制在一个class内,应该让他成为类的一个成员,而且为了该常量值使用一份实体,必须让其成为一个static成员如下所示:
1 class GamePlayer 2 { 3 private: 4 static const int NumTurns = 5; //常量声明式 5 int scores[NumTurns]; 6 ... 7 }
但是上面只是用到了NumTurn的声明式而非定义式通过用static来修饰上面这个式子使得只要不对其取地址,就可以如上声明并且使用。
但是如果想要取得一个class专属常量的地址的话,就必须为其提供一个定义式:
const int GamePlayer::NumTurns;
还有就是无法用#define来创建一个class专属常量,因为define不重视作用域。也就是#define不能用来封装,但是const成员变量则是可以的。
有时候使用static成员目的无法达到的话可以使用enum来实现,例如:
再者,对于通过预处理器实现的宏,例如
class GamePlayer { private: enum {NumTurns = 5}; int scores[NumTurns]; ... }
因为取得一个enum的地址是非法的,所以如果想禁止别人获得一个pointer或者reference指向某个整数常量,enum可以帮助实现这个约束
#define CALL_WITH_MAX(a,b) f((a) > (b) ? (a):(b))
则可以使用inline函数来进行代替,只要使用一个template inline 函数就可以了:
template<template T> inline void callWithMax(const T & a, const T & b) { f(a > b ? a : b); }
总结一下,这一节主要有两个要点,
- 对于单纯的常量,最好用const对象或者是enum来代替#define
- 对于类似函数的宏,最坏使用inline函数来进行代替