条款02:尽量以const,enum,inline替换#define
const替换#define
这个条款的另一个意思就是使用编译器替换预编译器,我们知道#define的内容都发生在预编译时期,所以有时稍不留神就会出错。
比如你写了下面这个代码:
#define PI 3.1415
PI这个记号可能从未被编译器看见,它可能在编译器处理源码之前就被预编译器移走了,而且如果因为这个常量而报错的话,错误信息会提到3.1415出错,而不是PI。
解决方法就是,将代码改为:
const double Pi = 3.1415;//一般宏名称通常全部大写,这里改变写法,便于区别
使用常量会比使用#define生成更少的码,应为预编译器会盲目的把PI都替换为3.1415,这样目标码就会出现多份3.1415,而常量Pi不会发生这种情况。
另外,当你使用常量字符串时,应该使用两个const(为什么这样用,条款03会详细说明)
const char* const name = "Jack";
当然更推荐你使用string类
const std::string name("Jack");
还有一个值得注意的是class专属常量,为了使常量的作用域限制于class内,就要使常量成为成员常量,而为了使此常量至多有一份实体,就必须让他成为static成员。
class GamePlayer{
private:
static const int NumTurns = 5;//定义常量
int scores[NumTurns];//使用常量
};
如果你要在外部文件取得他的话,只需要写
const int GamePlayer::NumTurns;
因为NumTurns已经有了初始值,所以不用继续赋值。
enum替换#define
你也可以使用enum枚举
#include<iostream>
class GamePlayer{
private:
enum{
NumTurns = 2;
};
int scores[NumTurns];//使用常量
};
我们把这种叫做enum hack,它在行为方面更像一个#define而不像const,取一个const的地址是合法的,但是enun和#define的就是不合法的。
inline替换#define
对于一个比较大小的宏函数,通常写法如下:
#define CALL_WITH_MAX(a, b) ((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 T& callWithMax(const int& a, const int& b){
return a > b ? a : b;
}
总结
请记住:
- 对于单纯常量,最好以const或者enums替换#defines
- 对于函数形式的宏,最好改用inline函数替换#defines;