条款2:尽量使用const ,enum,inline替换define

宁可使用编译器而不用预处理器

  假设我们使用预处理器:

#define ABC 1.56

  这标识符ABC也许编译器没看到,也许它在编译器处理源码前就被预处理器移走了,于是“标识符”ABC没有进入标识符列表(symbol table)中。但是当我们编译程序遇到个错误信息时,可能会带来困惑,因为这个错误信息可能会提到1.56而不是ABC,而下面例子在vs2015上编译的时候,错误信息提示ABC未定义的标识符。假如这个ABC不在我们自己定义的头文件中,我们根本无法知道其来源,追踪不到它。
解决之道就是使用一个常量代替宏定义:

const double abc=1.56;

  这样的话abc就是一个标识符,肯定会被编译器看到,必然会进入标识符列表。

 1 #include<iostream>
 2 using namespace std;
 3 
 4 #define ABC 3
 5 const int a = 3;
 6 
 7 int func(const int* n)
 8 {
 9     return *(n + 1);
10 }
11 
12 int main(void)
13 {
14     int x,y;
15     x = func(&ABC);//vs2015会提示表达式必须为左值或者标识符
16     cout << x << endl;
17     
18     y = func(&a);
19     cout << y << endl;
20     return 0;
21 }

常量定义特殊情况说明:
  (1).由于常量定义被放在头文件中,指针声明为const,假如是char*字符串的话,const就要写两次。

const char* const str="Burgess";

  string对象往往写成:

const std::string("Burgess");

  (2).class专属常量。为了将作用域限定在class内,必须使它成为一个成员变量。为了保证这个常量只有一个实体,要将它声明为static。

1 class A
2 {
3 private:
4 static const int Num=5;//常量声明式
5 int scores[Num];//使用该常量
6 };

  一般情况下,我们还需要在class外进行定义它。

const int A::Num;

  由于已经在类里面设了初值,这里不必再初始化。(旧编译器不支持在类里面为static const常量设初值),那么就要:

1 class A
2 {
3 private:
4 static const int Num;//声明式
5 };
6 const int A::Num=5;//定义式

这个定义式放在实现文件而不是头文件中。
需要说明的是,类里面的函数使用这个变量时,也需要声明为static。
假如上面的数组大小坚持使用一个标识符来代替怎么办呢,因为编译器必须在编译期间知道数组大小,那么我们就可以使用一个枚举类型的数值代替int型数值。

1 class A
2 {
3 private:
4 enum{Num=5};
5 int scores[Num];
6 };

这里enum类似#define,不能取地址,只需要获取其值。假如我们不想让别人获取指向某个常量的指针或者引用,可以使用enum。
让我们再返回宏定义。举个误用宏定义的例子。有时我们使用#define实现类似函数的宏定义,但是没有函数调用引来的额外开销。看下面:

 1 #define CALL_MAX(a,b) ((a)>(b))?(a):(b)
 2 int main(void)
 3 {
 4     int ret1,ret2,a = 5, b = 0;
 5     ret1 = CALL_MAX(++a, b);//现在a=7,不可思议
 6     cout<< ret1<<endl;
 7 
 8         ret2 = CALL_MAX(++a, b+10);//a=6
 9     cout <<  ret2 << endl;
10     return 0;
11 }

为什么 CALL_MAX(++a, b+10),此时a=6?
把参数代入表达式就可以知道:

((++a)>(b+10))?(++a):(b+10)

可以看成6>10吗,显然不是。那么就返回b+10=10,而不再执行++a,故a也不会再加1了。

如果不想要这种未知行为的#define,但是还想要宏定义的效率、安全性和可预知性(一切掌握在我们自己手里),那么inline模板函数是个好选择:

1 Template <typename T>
2 inline T const& max1(const &T a,const &T b)
3 {
4 return (a>b) ? a : b;
5 }

  这样的话,不会出现上面#define出现的++a加1进行了两次的情况,此时max1是真正的函数。

请记住:
  (1).单纯的常量,最好使用const或者enum代替#define;
  (2).类似函数的宏,最好以inline函数代替#define。

 

posted @ 2017-05-04 01:22  弗莱曼飞侠  阅读(270)  评论(0编辑  收藏  举报