條款02:儘量以const,enum,inline替換#define
const替換#define
這個條款的另一個意思就是使用編譯器替換預編譯器,我們知道#define的內容都發生在預編譯時期,所以有時稍不留神就會出錯。
比如你寫了下面這個代碼:
#define PI 3.1415
PI這個記號可能從未被編譯器看見,它可能在編譯器處理源碼之前就被預編譯器移走了,而且如果因爲這個常量而報錯的話,錯誤信息會提到3.1415出錯,而不是PI。
解決方法就是,將代碼改爲:
const double Pi = 3.1415;//一般宏名稱通常全部大寫,這裏改變寫法,便於區別
使用常量會比使用#define生成更少的碼,應爲預編譯器會盲目的把PI都替換爲3.1415,這樣目標碼就會出現多份3.1415,而常量Pi不會發生這種情況。
另外,當你使用常量字符串時,應該使用兩個const(爲什麼這樣用,條款03會詳細說明)
const char* const name = "Jack";
當然更推薦你使用string類
const std::string name("Jack");
還有一個值得注意的是class專屬常量,爲了使常量的作用域限制於class內,就要使常量成爲成員常量,而爲了使此常量至多有一份實體,就必須讓他成爲static成員。
class GamePlayer{
private:
static const int NumTurns = 5;//定義常量
int scores[NumTurns];//使用常量
};
如果你要在外部文件取得他的話,只需要寫
const int GamePlayer::NumTurns;
因爲NumTurns已經有了初始值,所以不用繼續賦值。
enum替換#define
你也可以使用enum枚舉
#include<iostream>
class GamePlayer{
private:
enum{
NumTurns = 2;
};
int scores[NumTurns];//使用常量
};
我們把這種叫做enum hack,它在行爲方面更像一個#define而不像const,取一個const的地址是合法的,但是enun和#define的就是不合法的。
inline替換#define
對於一個比較大小的宏函數,通常寫法如下:
#define CALL_WITH_MAX(a, b) ((a) > (b) ? (a) : (b))
首先從書寫方法上面就可以看出十分繁瑣,而且有時還會發生不可避免的錯誤,例如下面這樣調用:
int a = 5, b = 0;
CALL_WITH_MAX(++a, b);//a被累加兩次
CALL_WITH_MAX(++a, b+10);//a被累加一次
爲了防止這種錯誤,我們可以使用template inline函數
template<typename T>
inline T& callWithMax(const int& a, const int& b){
return a > b ? a : b;
}
總結
請記住:
- 對於單純常量,最好以const或者enums替換#defines
- 對於函數形式的宏,最好改用inline函數替換#defines;