《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控制编译等等。总而言之,如果非必要,应该尽可能地避免使用宏。

**【注意】**对于常量,应该使用constenum代替宏;同样,可以使用模板和内联函数来代替宏函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值