hjk41的日志

Avatar

Effective C++ 笔记1: 用const和inline代替define

define的使用一般有几种情况:
1. 用来定义常量,如

#define pi 3.1415926


2. 用来定义小函数,如

#define max(a,b) ((a) > (b) ? (a) : (b))


3. 用于

#ifndef _DEBUG
...
#endif

这样的组合

对于第一种情况,可以用const代替;第二种情况可以用inline来代替;第三种情况现在还没有其它方案

用const代替define来定义常量
因为define定义常量只是在编译之前用其值来代替符号(如上面的例子中是用3.1415926代替 pi ),所以如果在编译时出了错误,错误可能比较难发现。因为编译器只看到3.1415926这个数,而看不到 pi 这个符号,所以提示信息里很可能只会告诉你3.1415926这个数出现的地方有错,这时你就得去找3.1415926这个数到底在哪里定义的。
而如果用const float pi=3.1415926来定义就要简单得多了,出错信息会告诉你是 pi 出了错,这就简单多了。

用inline代替define来定义函数
define定义函数的最大缺点就是它只是简单替换,所以函数的参数可能会改变函数的行为。
比如上面定义的max,如果有这么一段代码:

int a = 5, b = 0;
max(++a, b);         // a is incremented twice
max(++a, b+10);      // a is incremented once


可以看到对两次调用,++a执行的次数是不一样的。而如果用inline,写成如下形式:

inline int max(int a, int b) { return a > b ? a : b; }


就不会有这个问题了。

其它相关问题
在class里定义常量
有时候我们希望常量只在一个类里有效,比如:

template <class T>
class set{
    static const int DefaultSize=10;
public:
    set(){data=new T[DefaultSize];}
protected:
    T * data;
}


按照标准,还应该在实现文件里加一句

const int set::DefaultSize;


但即使不加,这样的语法在VC++.NET里也不会出错。

在一些比较古老的编译器里这样的语法就会出错了,比如在VC++6.0里就不行,它不允许在类的声明文件里初始化 DefaultSize,所以我们只能这么写:

template <class T>
class set{
    static const int DefaultSize;
public:
    set(){data=new T[DefaultSize];}
protected:
    T * data;
}


然后在类的实现文件里写

const int set::DefaultSize=10;


但这里又有个问题,如果我们的代码这么写,就出问题了:

template <class T>
class set{
    static const int DefaultSize;
protected:
    T data[DefaultSize];
}


在初始化 data 时,DefaultSize 还没被赋值。怎么办呢,只能这么写了:

class GamePlayer {
private:
  enum { NUM_TURNS = 5 };    // "the enum hack" — makes
                             // NUM_TURNS a symbolic name
                             // for 5
  int scores[NUM_TURNS];     // fine
...
};


这个方法很变态,但这也是没办法的办法了。


评论已关闭