《Effective C++》Item2:尽量以const、enum、inline代替#define
宏的问题在于:处理它的是预处理器,而不是编译器。考虑如下的定义:
#define PI 3.1415926
在预处理器工作时,会将实际代码中的所有PI
都直接替换为3.1415926
,所以编译器在工作的时候根本看不到PI
这个记号。由此产生的问题是:PI
没有进入编译器的符号表。于是当你使用PI
但是不幸收到一个编译错误时,其错误信息可能包含3.1415926
,而不是PI
。如果这个宏不是由你定义的,那么这个错误很可能给你造成很大的困扰。
解决这个问题的一个方法是使用常量替换掉这个宏:
const double PI = 3.1415926;
这种做法有两种情况值得探讨:
- 第一是定义常量指针。由于常量定义式通常被定义在头文件中,因此有必要给指针添加顶层const:
const char *AuthorName = "zhangkeyang";
- 第二是定义类中的常量。为了将常量的作用于限制在某个类中,必须将这个常量定义为类的静态成员:
class Article
{
public:
static const std::string AuthorName;
//...
};
然而要注意,这里第四行的写法是声明
而非定义
(也就是说编译器实际上并没有为这个字符串常量分配内存空间)。我们必须在某个源文件中手动做这件事:
const std::string Article::AuthorName("zhangkeyang");
我们无法使用#define
来定义类专属常量,因为宏是不区分作用域的。
以上讨论了const
代替宏的有效做法。但是这种做法存在一种问题,就是对于在类内定义数组时,需要指定固定的长度;然而有些编译器不允许在声明类中的整型常量的同时初始化。此时,可以采取enum
来代替宏:
class GamePlayer
{
enum { NumTurns = 5 };
int scores[NumTurns];
};
枚举的实现方法很像宏:它们都没有内存分配的动作,并且都不可被取地址,但是枚举却确确实实进入了编译器的符号表。因此,对于整数型的常量,可以考虑使用枚举来代替宏。
在传统的C语言程序中,宏同时被用来定义方便而简短的“函数”——看上去非常像函数,但是却没有函数调用的运行时开销:
#define min(x, y) ((x) > (y) ? (y) : (x))
这般长相的宏有着太多的缺点。首先,你不得不为所有的参数都添加括号,这很影响阅读;即便如此,这种宏仍然会产生意料不到的错误。考虑如下写法:
int a = 5, b = 0;
min(a++, b);
我们的初衷是在调用结束后a
只递增一次,但实际情况是它被递增了两次。
解决以上问题的良药是内联。使用inline
关键字,C++代码可以实现得更为优雅和高效:
template<typename T>
const T &min(const T &x, const T &y)
{
return x > y ? y : x;
}
这个函数模板解决了上述所有的问题。
目前位置,我们已经介绍了足够多的替换原始宏的做法。但是,宏在有些方面仍然是不可替代的,比如使用#ifndef/#define
控制编译等等。总而言之,如果非必要,应该尽可能地避免使用宏。
**【注意】**对于常量,应该使用const
或enum
代替宏;同样,可以使用模板和内联函数来代替宏函数。
上一篇: Java基础---引用类型和值类型
推荐阅读
-
Effective C++ item01 尽量以const enum inline替换#define
-
《Effective C++》Item2:尽量以const、enum、inline代替#define
-
条款 02:尽量以 const, enum, inline 替换 #define
-
条款02:尽量以const, enum, inline替换 #define
-
条款02: 尽量以const,enum,inline替换 #define
-
条款 02 - 尽量以const、enum、inline替换#define
-
条款 02:尽量以 const,enum,inline 替换 #define
-
条款02:尽量以const、enum、inline替换 #define
-
条款02:尽量以const、enum、inline替换#define
-
条款02:尽量以const,enum,inline替换#define