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

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

1、const

#define ASPECT_RATIO 1.653

在预处理的时候,会使用实际值替换宏名,程序中所有的ASPECT_RATIO 替换为1.653.

会出现的问题:这个宏的记号名称在预处理的时候就被替换为数字,不会进入编译器阶段的符号表,出错的时候,是提示一串数字。

解决方法:使用一个常量const来替换上述的宏:

const double ASPECTRatio = 1.653

注意:使用宏可以定义数组的大小,编译不会报错,使用const也可以,int a[ASPECTRatio].

有两种特殊情况需要注意!

1)定义常量指针。

const char* const authorName = "Scott Meyers";

*之前的是底层const,说明指向的数组是常量,数据不能更改,*之后的是顶层const,说明指针是个const,指针的指向不能更改,但是数据可以。

2)class专属常量。

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

class GamePlayer{
private:
     static const int NumTurns = 5;//常量声明式
     int scores[NumTurns];
     ...
};
//下面的定义式放在cpp文件而不是头文件里面
const int GamePlayer::NumTurns;//定义式

由于class常量已经在声明的时候获得初值,因此定义时不可以再设初值。

扩展:

//声明和定义的区分:
//extern是声明,在类内的变量是声明,有函数体的是定义,其他都是定义。变量和对象不加extern永远是定义,类中除外

 

注意:#define的定义域只有遇到#endef才结束,所以无法定义一个class专属常量。

老的编译器不支持static成员在声明的时候赋予初值,那么只有在定义时赋初值。还可以使用枚举类型进行赋值操作。

2、enum

枚举类型补充知识:

枚举类型使我们可以将一组整型常量组织在一起。和类一样,每个枚举类型定义了一种新的类型。枚举属于字面值常量类型。

 枚举类型分为限定作用域的和不限定作用域的。

  • 限定作用域的 
enum class open_modes{input,output,append};
open_modes nw = open_modes::inout;//需要使用作用域运算符显式的调用枚举成员

默认情况下,枚举值从0开始,一次加1,也可以显式的赋初值,枚举成员是const。

  • 不限定作用域的
enum color{red,yellow,green};
enum{red1,yellow1,green1};

名字的作用域就是enum所在的作用域,所以两者的名字不能重复。,可以直接使用{}里面的元素进行赋值操作。

和类一样,枚举也可以定义新的类型,不过必须要使用enum进行赋值。

class CostEstimate{
private:
     enum{Numturns= 5};
     int scores[Numturns];

};

和#define相似的地方:取一个enum的地址是不合法的,而且它不会导致非必要的内存分配。

3、inline

问题的提出:

//以a和b的较大值调用f
#define CALL_WITH_MAX(a,b) f((a) ? (b) : (a) : (b))

CALL_WITH_MAX(++a,b);

a的递增次数取决于a和b哪个大,无法预料行为,所以使用template inline函数。

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

 

总结:

  1. 对于单纯变量,最好以const对象或enum替换define;
  2. 对于形似函数的宏,最好改用inline函数替换define。

 

posted @ 2017-12-10 16:55  zqlucky  阅读(347)  评论(0编辑  收藏  举报