欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

D45.1.0 尽量用const enum inline 替换 #define

程序员文章站 2024-03-23 13:42:22
...

01 使用const替换#define

通常,我们很习惯在程序起始位置写出#define ASPECT_RATIO 1.653的语句。这样的定义往往会有如下隐患:

  • ASPECT_RATIO从未被编译器看见,可能在编译器开始处理源码之前就被预处理器移走了。名称ASPECT_RATIO可能没进入记号表内,于是会出现变异错误的信息。

  • ASPECT_RATIO定义在一个非我们缩写的文件头内时,然后我们肯定要花时间去寻找1.653来自哪里。

使用如下定义:

const double AspectRatio = 1.653;

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

02 使用enum替换#define

#define NumTurns 5

class GamePlayer
{
private:
    int scores[NumTurns];
}

上述代码中,我们无法利用#define创建一个class专属常量,因为一旦宏被定义,它就在后面的编译过程中有效。#define不仅不能够用来定义class常量,也不能提供任何封装性。这时候可以使用枚举类型,其理论基础是“枚举类型的数值可以充当int型使用”。于是,GamePlayer可定义如下:

class GamePlayer
{
private:
    enum { NumTurns = 5 };
    int scores[NumTurns];
}

使用enum可以防止别人获取整数常量的地址或者引用,因为获取enum的地址是不合法的,而获取const的地址是合法的。

03 使用inline替换#define

宏还可以用来实现函数定义,如:

//a和b较大值调用f
#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的递增次数取决于b。通过使用template inline函数可以获得宏带来的效率以及一般函数所有可预料行为和类型安全:

template<typename T>
inline void callwithMax(const T& a, const T& b)
{
    f(a>b?a:b)
}

这个template产出一群函数,每个函数都接受两个同型对象,并以其中较大者调用f。这种写法方便阅读,并且callwithMax是个真正的函数,它遵守作用域和访问规则。