【Effective C++ 读书笔记】条款02: 尽量以 const, enum, inline 替换 #define

条款02: 尽量以 const, enum, inline 替换 #define

这个条款或许可以改为“宁可以编译器替换预处理器”。
编译过程:
.c文件--预处理-->.i文件--编译-->.o文件--链接-->bin文件

如果你做出这样的事:

#define ASPECT_PATIO 1.653

记号名称 ASPECT_PATIO 从未被编译器看见;也许在编译器开始处理源代码之前它就被预处理器移走了。于是记号名称 ASPECT_PATIO 有可能没有进入符号表(symbol table)内。于是,当你运用此常量但获得一个编译错误信息时,可能会带来困惑。因为这个错误信息也许会提到 1.653 而不是 ASPECT_PADIO 。

解决之道是以一个常量替换上述的宏(#define):

const double AspectRatio = 1.653;

当我们以常量替换#define时,有两种特殊情况:

  • 定义常量指针
const char * const authorName = "Scott Meyers";
//前一个 const 声明 authorName 是一个指向 char 类型的const对象的指针;
//后一个 const 声明 authorName 是一个指向 char 类型对象的 cosnt 指针。
  • class 专属常量
class GamePlayer{
private:
    static const int NumTurns = 5; //常量声明式
    int scores[NumTurns];          //使用该常量
};

然而你所看到的是 NumTurns 的声明式而非定义式。通常C++ 要求你对你所使用的任何东西提供一个定义式,但 如果他是个 class 专属常量又是 static 且为整数类型(integral type,例如 ints, chars, bools),则需特殊处理。只要不取他们的地址,你可以声明并使用它们而无须提供定义式。
但如果你取某个 class 专属常量的地址,你就必须另外提供定义式如下:

const int GamePlayer::NumTurns; //NumTurns 的定义

当你的编译器不允许”static 整数型 class 常量 完成 in class 初值设定“,你可以将初值放在定义式:

class CostEstimate{
private:
    static const double FudgeFactor;  //static class 常量声明

                                    //位于头文件内
}

//class 常量定义;位于实现文件内
const double
    CostEstimate::FudgeFactor = 1.35;

然而,万事总有例外,当你在 class 编译期间需要一个 class 常量值,例如在上述的 GamePlayer::scores 的数组声明中(编译器坚持必须在编译期间知道数组的大小),而且你的编译器恰好不支持 ”static 整数型 class 常量 完成 in class 初值设定“,你可以改用所谓的“the enum hack”补偿做法:

class GamePlayer{
private:
    //令NumTurns 成为 5 的一个记号名称,这就没问题了
    enum { NumTurns = 5};
    int scores[NumTurns];
};

另一常见的#define 误用情况是以它实现宏(macros)。宏看起来像函数,但不会招致函数调用带来的额外开销。
但是:
宏有着太多的缺点,代码晦涩难懂让人痛苦不堪。

inline 函数可以带来宏的效率以及一般函数的所有可预料行为和类型安全性。

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

请记住:

  • 对单纯常量,最好以 const 对象 或 enums 替换 #define.
  • 对于形似函数的宏 macros, 最好改用 inline 函数替换 #define

原文地址:https://www.cnblogs.com/lanqiu5ge/p/9472210.html