• 条款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。

  • 相关阅读:
    属性选择器(通常用在input)
    函数调用的文档注释
    List集合操作
    数组排序三种方法
    字符串反序输出字符串
    js中完美运动框架
    查找100-200之间是否存在水仙花数
    提示用户输入一个正整数,如果错误,则重新输入,可以使用以下的代码来保证用户输入正确:
    Ubuntu 16.10下的 jdk 1.8.0_111
    方法内部类
  • 原文地址:https://www.cnblogs.com/Burgess-Fan/p/6804998.html
Copyright © 2020-2023  润新知