宁可以编译器替换预处理器
这个条款获取改为“宁可以编译器替换预处理器”比较好,因为或许 #define不被视为语言的一部分。那正是问题所在。当你做出这样的事情:
#define ASPECT_PATIO 1.653
记号ASPECT_PATIO 也许从未被编译器看见;也许在编译器开始处理源码之前它就被预处理器移走了(#define 的变量单纯被替换)。于是记号名称有可能没进入记号表。当运用此常量但获得一个编译错误信息时,可能会带来困惑,因为这个错误信息也许会提到1.653而不是ASPECT_PATIO。
解决之道是以一个常量替换上述的宏:
const double AspectRatio = 1.653; //大写的名称通常用于宏,这里改变名称写法
作为一个语言常量,AspectRatio 肯定会被编译器看到,当然会进入记号表内。此外对浮点常量而言,使用常量可能比使用#define导致较小量的码,因为预处理器“盲目地将宏名称ASPECT_PATIO 替换为 1.653”可能导致目标码出现多份1.653,若改用常量AspectRatio 绝不会出现相同情况。
两种特殊情况
- 定义常量指针
const char * const authorName = "Scotte";
或
const std::string anthorName("Scotte");
- class专属常量
为了将常量的作用域限制于class内,你必须让它成为class的一个成员(member)‘而为确保此常量之多只有一份实体,必须声明为static
class GamePlayer
{
private:
static const int NumTurns = 5; //常量声明式
int scores[NumTurns]; //使用该常量
};
若要取专属常量的地址,则还需要在类的实现文件中提供如下定义
const int GamePlayer::NumTurns; //变量的定义,没有初值,因为在上面声明时已经获得初值。
#define不仅不能够用来定义class专属常量,也不能够提供任何封装性。
旧式的编译器不支持上述语法,可以将初值放在定义式
class CostEstimate
{
private:
static const double FudgeFactor; //声明位于头文件
};
const double CostEstimate::FudgeFactor = 1.35; //常量定义位于实现文件
还可以使用 "the enum hack"补偿
class GamePlayer
{
private:
enum{ NumTurns = 5 }; //令NumTurns 成为5的一个记号
int scores[NumTurns];
};
宏实现函数
//以a和b的较大值调用f
#define CALL_WITH_MAX(a, b) f((a) > (b) ? (a) : (b))
存在问题
int a = 5, b = 0;
CALL_WITH_MAX(++a, b); //a被累加二次
CALL_WITH_MAX(++a, b + 10); //a被累加一次
使用template inline函数代替
template<typename T>
inline void callWithMax(const T &a, const T &b)
{
f(a > b ? a : b);
}
请记住
- 对于单纯常量,最好以const对象或enums替换#defines
- 对于形似函数的宏,最好改用inline函数替换#defines.