在C++中基本上不需要宏。宏对包含卫哨(guard)是有用的(参见2.4节),极少情况下,宏在一个.c文件中带来的好处大于弊端(用于为可移植性或调试实现条件编译时,最为显著)。在一般情况下,预处理宏对于软件产品是不合适的。
主要设计规则
除非作为包含卫哨,否则应该避免在头文件中使用预处理宏。
预处理器不是C++语言的一部分,其基本成分完全是文本,极其难以调试。尽管宏可以让代码更容易编写,但是它们的自由形式经常使得代码更难阅读和理解。请看下列代码片段:
在源代码层次上,我们如何让调试器、浏览器和其他自动工具处理上面的代码片段?
这和在.c文件中包含宏一样糟糕,甚至有更充足的软件工程理由要求头文件不包含宏。以在一个头文件中用#define定义一个预处理常量为例。由于宏不是C++的一部分,它们不能够被放置在一个类的作用域内。任何包含一个带有#define的头文件的文件都将具有该预处理常量的定义。
假设theircode.h定义了一个常量值GOOD作为一个预处理常量:
对于上面这段代码,当编译ourcode.c文件时,编译器首先调用预处理器。即使GOOD在一个函数作用域的保护下定义,它对于预处理器也是不安全的,预处理器将毫不留情地以字面整数0替代枚举器GOOD:
当编译器遇到枚举时,会弹出Syntax Error(语法错误),你却不知道这是为什么,直到花费很长时间“grepping”出.h文件中有人已经用#define定义了枚举成员之一。注意,如果在文件作用域中预处理器符号由const或enum代替,这个问题将不会发生(顺便提一下,根据2.3.3节,这也违反了设计规则)。
在缺少或没有充分实现C++语言特性的情况下,预处理器宏也可以用于实现模板功能。如果宏用于此目的,那么宏函数将出现在头文件中。除了借助宏,也有其他解决这个问题的方法,这些方法可以更好地适应大型项目。无论如何,与模板相关的问题应在开发过程的早期解决。