effect C++ 尽量以const, enum, inline 替换 #define

来源:互联网 发布:妇女社会地位调查数据 编辑:程序博客网 时间:2024/05/21 11:02

宁可以编译器替换预处理器

  #define 不被视为语言的一部分

#define ASPECT_RATIO 1.653

    ASPECT_RATIO也许从未被编译器看见,或许在编译器开始处理源码之前就被预处理移走了。于是当你运用此常量但获得一个编译错误信息时,可能会带来困惑,因为这个信息会提到的是 1.653 而不是 ASPECT_RATIO 。 如果 ASPECT_RATIO被定义在一个非你写的头文件中,你肯定对 1.653以及它来自何处毫无概念,将因为追踪它而浪费时间。

解决之道,以一个常量替换宏

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

常量定义的两种特殊情况

 定义常量指针

由于常量式定义通常被放在头文件内(以便被不同的源码含入),因此有必要将指针(不是指针指向之物)声明为const.若要在头文件内定义一个常量字符串


const char * const authorName = "Scott Meyers";
const std::string authotName="Scott Meyers";

class专属常量

为了将常量的作用域限制域class内,必须让它成为一个class的成员;而为确保此常量至多只有一份实体,必须让它成为一个static成员。

        

class GamePlayer{private:  static const int NumTurns = 5 ; //常量声明式  int scores[NumTurns];          //使用该常量  ...};

    通常C++要求对使用的任何东西提供一个定义式,但它如果是个class专属常量又是static且为整数类型(int ,char ,bool)需要特殊处理。职业不取它们的地址,你可以声明并使用它们而无需提供定义式。但如果你取某个class专属常量的地址,或者编译器要求需要一个定义式,必须如下提供

const int GamePlayer:: NumTurns   //NumTurns 定义
把这个式子放进一个实现文件而非头文件。由于class常量已在声明时获得初值。定义时不可以再设初值。

我们无法使用#define创建一个class专属常量,因为#define并不重视作用域。一旦宏被定义,它就在其后的编译过程中有效(除非某处被#undef。这就意味着#define不仅不能够用来定义class专属常量,也不能提供任何封装性。const成员是可以被封装的。

使用enum

一个属于枚举类型的数值可权充int被使用

class GamePlayer{private:   enum{ NumTurns =5 };   int scores[NumTurns];
使用enum 代替 #define 。enum在行为方面更像#define 更不像 const。例如:取一个const 的地址是合法的,取一个enum的地址就不合法,而取#define的地址也是不合法的。如果不想让别人获得一个指针或者引用指向你的某个整数常量,enum可以帮你实现这个约束。

形式函数的宏

宏看起来像函数,但不会招致函数调用带来的额外开销。

#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的递增次数竟然取决于“它被拿来和谁比较”。

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

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

这个template产生出一整群函数,每个函数都接受两个同型对象,并以其中较大者调用f。callWithMax是个真正的函数,它遵循作用域和访问规则。



有了consts 、enums和inlines,我们对预处理器(特别是#define)的需求降低了。但#include仍是必须品。

对于单纯的常量,最好以const对象或者enums 替换#define。

对于形式函数的宏,最好改用inline函数替换#define。

0 0
原创粉丝点击