Effective C++读书笔记之二:尽量以const,enum,inline替换#define

Item02:Prefer consts,enums,and inlines to #defines

#define不被视为语言的一部分,这正是其问题所在。当你做出这样的事情:
     
#define ASPECT_RATIO 1.653

记号ASPECT_RATIO也许从未被编译器看见;也许在编译器开始处理源码之前它就被预处理器移走了。于是记号名称ASPECT_RATIO有可能没进入记号表内。于是当你运用此常量但获得一个编译错误信息时,可能会带来困惑,因为这个错误信息有可能会提到1.653而不是ASPECT_RATIO。如果ASPECT_RATIO被定义在一个非你所写的头文件内,你肯定对1.653以及它从何而来感到困惑,于是你将因为追踪它而浪费时间

解决之道是以一个常量来替换上述的宏(#defien):  const double AspectRatio = 1.653

作为一个语言常量,AspectRatio肯定会被编译器看到,当然就会进入记号表内。此外对浮点常量而言,使用常量可能比使用#defien导致较小量的码,因为预处理器”盲目地将宏名称ASPECT_RATIO替换为1.653“可能导致目标码出现多份1.653,若改用常量绝不会出现相同情况。

如果要在头文件内定义一个常量的char*-based 字符串,你必须写const两次:
const char* const authorName = ”Scott Meyers“;
这里要注意的是,string对象通常比其前辈char*-based合宜,所以上述的authorName往往定义成这样更好些:
const std::string authorName("Scott Meyers");

为了将常量的作用域限制于一个class内,你必须让它成为class的一个成员,而为确保此常量之多只有一份实体,你必须让它成为一个static成员:
class GamePlayer
{
private:
	static const int NumTurns = 5;//常量声明式
	int scores[NumTurns];//使用该常量
	...... 
		
};

如果你取某个class专属常量的地址,或纵使你不取其地址而你的编译器却(不正确地)坚持要看到一个定义式,你就必须另外提供定义式如下:
const int GamePlayer::NumTurns;

把这个式子放进一个实现文件而非头文件。由于class常量已经在声明时获得初值,因此定义式可以不必再设初值。顺带一提,我们无法用一个#define创建一个class专属常量,因为#define并不重视作用域,一旦宏被定义,它就在其后的编译过程中都有效(除非在某处有#undef)。

旧式编译器可能不支持上述的语法,他们不允许static成员在其声明式上获得初值。此时你可以这么做:
class CostEstimate
{
private:
	static const double FudgeFactor;//static class常量声明放在头文件内 
	...
};
const double CostEstimate::FudgeFactor = 1.35//static class常量定义放在实现文件内 

而如果当你在class编译期间需要一个class常量值,例如上述的GamePlayer::score的数组声明中(是的,编译器坚持必须在编译期间知道数组的大小)。这个时候万一你的编译器(错误地)不允许”static 整数型 class常量“完成”in class 初值设定“,可改用所谓的”the enum hack“补偿做法。其理论基础是 “一个属于枚举类型的数值可权充ints被使用”,于是你可以这样做:
class GamePlayer
{
private:
	enum{
		NumTurns = 5
	};
	int scores[NumTurns];
}

Enums和#define一样绝不会导致非必要的内存分配。

另一个常见的#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的递增次数竟取决于“它被拿来和谁比较”!

//云风评注:max是永远地关于宏的反面案例。有兴趣的同学可以搜索一篇题为min,max and more的文章。//

但是你可以用如下的方式解决:
template<typenaem T>
inline void callWithMax(const T&a,const T&b)
{
	f(a>b?a:b);
}

请记住: 1.对于单纯常量,最好以const对象或enums替换#defines。
                2.对于形似函数的宏,最好改用inline函数替换#defines。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值