这个条款其实就是宁可以编译器替换预处理器,因为#define不被视为语言的一部分,比如:
#define ASPECT_RATIO 1.653
在编译器处理源码前,ASPECT_RATIO就被预处理器替代成1.653了,因此,ASPECT_RATIO有可能没进入symbol table内,那么当编译或调试时,如果出现错误而ASPECT_RATIO又非你所在的头文件内,则你会对1.653是什么感到莫宁其妙而浪费跟踪时间。
一、const替代#define
解决上面问题的方法是以常量替换上述的宏:
const double AspectRatio = 1.653;
作为语言常量,AspectRatio肯定会被编译器看到,并进入symbol table内。
为了将常量作用于限制于class内,你必须让它成为class的一个成员即class专属常量,而为确保此常量至多只有一份实体,你必须让它成为一个static成员:
class GamePlayer{
private:
static const int NumTurns = 5; //常量声明式
int scores[NumTurns]; //使用该常量
...
};
需要注意的是:#define不重视作用于域,一旦宏被定义,则在其后整个编译过程中都有效,除非在某处被#undef了,这意味着#define不能用于定义class专属常量,也不能提供任何封装性,即private #define之类的东西。
如果编译器不支持前面这种声明方式,则你需要如下定义:
class CostEstimate{
private:
static const double FudgeFactor; //static class常量声明位于.h头文件内
...
};
const double CostEstimate::FudgeFactor = 1.35 //static class常量定义位于.cpp源文件内
当然这不适合用于前面GamePlayer::scores的数组声明式,因为编译器在编译期间需要知道数组大小即需要一个class常量值。
如果编译器不支持而你又有这种声明数组的需求,则可用“the enum hack”补偿做法来实现。
二、const替代#define
如下来重新定义GamePlayer:
class GamePlayer{
private:
enum {NumTurns = 5}; //"the enum hack"
int scores[NumTurns];
...
};
三、inline替代#define
为了减少函数调用开销我们通常用宏来代替函数,但是宏夹带着实参时,参数必须加上小括号,否则后果很严重,但是即便如此还是会有问题,比如:
#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被累加一次
在这里,调用f之前,a的累加此时竟然取决于”它被拿来和谁比较“!是不是严重偏离初衷了?
大杀器来了,template inline函数能让你获得宏的效率以及一般函数的所有可预料行为和类型安全性:
template //因为类型不确定
inline void CallWithMax(const T &a, const T &b) //T可能是有比较操作符的对象,因此,用引用
{
f (a > b ? a : b);
}
需要注意的是:对于单纯常量,最好以const对象或enums替换#define;对于形似函数的宏,最好用inline替换#define。
阅读(8561) | 评论(9) | 转发(3) |