首选在宏替换是在预处理阶段进行,记住宏替换是最最最最简单的方式进行替换,也仅仅是做替换
原因一:因为宏是进行最简单的宏替换,因此如果出现以下的情况
#define ASPECT_PATIO 213
在程序中所有的ASPECT_PATIO都被替换成213,可能会存在这样一个情况,使用了这个宏,但是出现了一个错误,但是编译器不会提到ASPECT_PATIO,反而会提到213,这样就可能存在一个情况,如果这个宏是我们自己定义的,我们可能会知道是什么错误,但是这个宏要是不是我们定义的,我们就很难知道错误在哪里。解决办法就是
const double Aspectpatio =213;
编译器在生成目标代码(obj)的时候,对于简单的宏替换可能会导致目标代码出现多份“213”,但是对于变量不会出现这个问题(本人没学过编译原理等底层课程,所以不知道编译器生成目标代码的过程)。
同时通过常量替换#define的时候需要注意两种情况:
①定义常量指针的时候使用string的常量对象更合适:
const char * const authorname="meyers"; //指针指向一个常量,不能通过指针修改常量值,指针指向也不能改
const std::string authorname ="meyers";
②如果是class的专属常量,需要将这个常量限制在class中,作为static成员
class GamePlayer
{
private:
static const int Numturns;
}
const int GamePlayer::Numturns=5;
但是这种情况可能也不适合某种情况,例如:数组声明必须知道数组的大小,编译器不允许“static 整数型 class常量”完成数组的大小设定, 可以通过枚举在解决这种情况。
了解一下枚举:①枚举在某些方面比较像#define,取一个const变量的地址一般是合法的,但是取一个枚举类型或者一个#define类型就不合法,如果你不想别人的指针或者应用指向你的某个变量,枚举是一个选择。②事实上 enum back是模板元编程的基础
class GamePlayer
{
private:
enum{Numturns=5};
int scores[Numturns]; //枚举值是常量不是变量
}
原因二:宏没有安全检查,可能存在安全隐患
注意在定义宏的时候为所有的实参加上小括号,这样能保证减少错误,但是不能完全避免错误,看下 下面的代码,
#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次
a的递增次数在于和谁比较,因为宏仅仅做了替换,最简单的替换。这是不安全。我们可以通过内联函数的形式来替换这样的宏
template<typename T>
inline void CallWithMax(const T &a,const T &b ) //不知道T是什么类型,采用pass-byreference-to-const
{
f(a>b?a:b);
}
这里的CallWithMax是个真正意义的函数,遵循作用域和访问规则,这样就是安全的