[Effective C++]条款02:尽量以const,enum,inline 替换#define
Prefer consts,enums,and inlines to #defines.
我们学习C语言的时候,经常会用到预处理器语句,比如#define,#include,#ifdef,#endif.预处理语句是无法被编译器看见的,所以无法得到有效的错误提示.比如说:
#define ASPECT_RATIO 1.653
记号名称ASPECT_RATIO有可能没有进入记号表(symbol table)内.于是当你运用此常量获得一个编译错误信息时,错误信息的提示会提到1.653而不是ASPECT_RATIO,如果ASPECT_RATIO被定义在一个非自己写的头文件内,这样我们就需要花费时间去追踪错误.但想想是不是真的需要花费这样子的时间来纠正错误哪?其实用const替换#define就可以解决这个问题.
const double AspectRatio=1.653;
因为const会被编译器看到,当然就会进入记号表内.错误提示的时候也就能很快的定位错误.
另外使用const还能产生比使用#define更小的码.因为预处理器盲目的将所有的ASPECT_RATIO替换为1.653,而改用常量则不会出现这种情况.
常量替换#defines的特殊情况:
(1)定义常量指针
(2)class专属常量:作用域和static,作用域确保常量限制于class内.static确保此常量至多只有一份实体.
另外,无法利用#define创建一个class专属常量.
如果编译器不允许"static整数型class常量"完成"in class初值设定",可改用所谓的"the enum hack"的补偿做法.理论基础是"一个属于枚举型的数值可权充ints被使用",例如:
class GamePlayer{
private:
enum {NumTurns=5};
int scores[NumTurns];
}
enum hack值得认识的两个理由:
(1)enum hack的行为某方面说比较像#define而不像const.例如取地址,作用于const常量中是合法的,但作用于enum和#define就是不合法的.
(2)实用主义.
#define可以用来实现宏(macros),但宏确实有着很多缺点,比如说:
#define CALL_WITH_MAX(a,b) f((a)>(b))?(a):(b));
当使用int a=5,b=0; CALL_WITH_MAX(++a,b);调用的使用a被累加了两次.但宏的优点也是有的,它不会招致函数调用带来的额外开销.
为了获得宏带来的效率以及一般函数的所有可预料行为和类型安全性(type safety)---使用template inline代替它是很好的选择.
而且如果你要实现一个"class内的private inline函数"#define是做不到的.
后话总结:
对于单纯的常量,最好以const或者enums替换#defines
对于形似函数的宏,最好改用inline函数替换#defines