您的位置:首页 > 其它

尽量避免使用#define

2013-05-03 14:50 155 查看
#define是预处理的内容,本质上是为一个常量或者一个函数定义一个标识符,而在编译时代码中的标识符会被其真正的内容所替换,主要目的可以理解为提高代码的可读性。

但#define有其局限性,比如由于其是预处理器的内容,在编译时已经被真正的内容所替代,所以编译器很有可能看不到其标识符,那么在调试过程中就会出现迷惑,举个例子:

对于下面的宏:

#define PI 3.1415926


编译时代码中不会出现PI,但会出现很多3.1415926,这样出现错误信息时,你就只能看到3.1415926,而看不到它的标识符,也就难以理解这个数值所代表的意义。而同时,出现很多的3.1415926也会占用较多的空间。这两点都可以通过定义一个const常量所解决,与const常量相比,宏还具有如下的局限性:

1)无法定义常量指针;

2)无法创建一个class专属常量,因为它不重视作用域,一旦定义那么在其后的编译过程中都能够被看到,因此也不具有封装性。

对于第二点,可以通过在类中定义static常量实现,但static只能在类中被声明而不可以被定义,通常在实现中定义,例如:

public class Test
{
  private:
    static const int size = 10;//注意,这里赋了初值,但有的编译器不支持在类中赋初值
    int array[size];

  public:
    Test(){ };
};

const int Test::size;//这里不可以再赋初值,因为声明时已经赋了初值


如果编译器不支持在类中给static const常量赋初值,那么你就不能直接在上面的类中声明int array[size]了,因为编译器需要在编译期间知道数组的大小(因为要为数组分配空间?)

那么此时可以用enum方式来声明和定义一个int变量,方法如下:

public class Test
{
  private:
    enum { size = 5; }
    int array[size];
  public:
    Test(){ };
};


与#define和const常量相比,enum更像前者,因为可以对const常量取地址,但不可以对enum和#define取地址,因此enum可以防止程序员将一个reference或者pointer指向它所定义的常量。

3)#define可以定义类似函数的宏,它看起来像函数,但没有一般函数调用的开销,宏在某些情况下并不能像人们想象的那样运行,比如如下情况:

#define GETBIGGER(a,b) f( (a) > (b) ? (a) : (b))

int a=5, b=1;

GETBIGGER(++a, b); //a累加2次
GETBIGGER(++a, (b+10)); //a累加1次


此时,可以通过inline函数代替宏来改变这种情况,使用inline函数的好处是可以产生宏一样的效率,但同时具备一般函数的所有可预料行为以及类型安全检测,例如:

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


此外,inline函数也具有一般函数的作用域和访问规则,因此也可以作为类的成员进行封装,而#define定义的宏则不具备这种性质。

因此,在大多数情况下,#define都可以被const, enum或者inline函数所替代,此时应尽量避免使用#define。

以上内容,整理自Effective C++条款02。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: