理解
用编译器取代预处理器
const 取代 define
define
编译代码时,在预处理阶段进行宏替换,直接进行内容替换,编译器不会将定义的宏添加到符号表。所以如果有编译错误时,不会提示宏错误而是提示宏的具体内容。
举例:
#define ASPECT_RATIO 1.653
此处,编译的时候,ASPECT_RATIO 不会添加到符号表,而是在代码的每一处都会有一个 1.653,如果报错,那么也会有多处报错,提示是1.653这块出了问题,而不是ASPECT_RATIO 这里出了问题。同样在debugger时,也会遇到同样的问题(因为宏没有添加到符号表)。
const
const 修饰的变量使其成为常量,在编译过程中,编译器识别并添加到符号表中,且在使用const常量时,且地址唯一,不会产生拷贝。
const常量能很好的替代define,方便代码调试,且能产生更小的代码量。
注意:
1、const指针的特殊性,需要注意,详情请查看:const理解
2、类的常量。为了将一个const常量限制在一个class里面,必须将其作为一个类的成员,为了确保该常量只有一个拷贝(即在class内仅存在一份),必须声明为static成员。define宏是没有作用范围的(即没有“private”宏)
enums 取代 define
1、一般是用在整型替换上,这一点与const区别是,可以合法地取得一个 const 的 address(地址),但不能合法地取得一个 enum 的 address(地址),enum就是强制约束的好方法。(关于更多的通过编码的方法强制执行设计约束的方法,参见 Item 18。)
2、大量代码使用时,可以进行批量使用,是模板元编程的一项基本技术(参见 Item 48)
inlines 取代 define
从预处理器角度来看,#define 指令的另一个普遍的(不好的)用法是实现看来像函数,但不会引起一个函数调用的开销的 macros(宏)。以下是一个用较大的宏参数调用函数 f 的 macro(宏):
// call f with the maximum of a and b
#define CALL_WITH_MAX(a, b) f((a) > (b) ? (a) : (b))
这样的 macro(宏)有数不清的缺点,想起来就让人头疼。
无论何时,你写这样一个 macro(宏),都必须记住为 macro body(宏体)中所有的 arguments(参数)加上括号。
此时inline的模板函数就起到了作用:
template<typename T> // because we don't
inline void callWithMax(const T& a, const T& b) // know what T is, we
{ // pass by reference-to-
f(a > b ? a : b); // const - see Item 20
}
具体两者的区别与联系请查看:inline与define区别与联系
总结
为了得到 consts,enums 和 inlines 的可用性,你需要尽量减少 preprocessor(预处理器)(特别是 #define)的使用,但还不能完全消除。#include 依然是基本要素,而 #ifdef/#ifndef 也继续扮演着重要的角色。现在还不是让 preprocessor(预处理器)完全退休的时间,但你应该给它漫长而频繁的假期。
- 对于 simple constants(简单常量),用 const objects(const 对象)或 enums(枚举)取代
#defines。 - 对于 function-like macros(类似函数的宏),用 inline functions(内联函数)取代 #defines。