【Effective C++讀書筆記】條款02 盡量以const, enum, inline 替換 #define

條款02列了三種情況說明為什么要盡量以const,enum,inline替換#define。下面一一介紹。

1. const替換#define

#define ASPECT_RATIO 1.653

當(dāng)你使用#define時(shí),在編譯器進(jìn)行編譯之前,預(yù)處理器會(huì)將所有的ASPECT_RATIO替換為1.653。所以我們可能會(huì)遇到這種情況,就是當(dāng)出現(xiàn)一個(gè)編譯錯(cuò)誤時(shí),錯(cuò)誤信息會(huì)提到1.653,而不是ASPECT_RATIO,因?yàn)樵诰幾g之前ASPECT_RATIO已被替換。當(dāng)程序很大時(shí),我們對(duì)1.653來自何方毫無概念,對(duì)于追蹤它會(huì)浪費(fèi)很多時(shí)間。
解決的方法是以一個(gè)常量替換上述的宏(#define):

const double AspectRatio = 1.653;

書中下面這段話我沒太明白啥意思,看懂的可以留言互相討論。

對(duì)浮點(diǎn)常量(floating point constant, 就像本例)而言,使用常量可能比使用#define導(dǎo)致較小量的代碼,因?yàn)轭A(yù)處理器“盲目地將宏名稱ASPECT_RATIO替換胃1.653”可能導(dǎo)致目標(biāo)碼(object code)出現(xiàn)多份1.653,若改用常量AspectRatio絕不會(huì)出現(xiàn)相同情況。

使用const有兩點(diǎn)需要注意的地方:

1)常量指針

若要在頭文件中定義一個(gè)常量指針,必須寫兩次const。

const char* const authorName = "Scott Meyers";
2)class專屬常量
class GamePlayer {
private:
  static const int NumTurns = 5;  // 常量聲明式
  int scores[NumTurns];
}

static保證了常量至多只有一個(gè)實(shí)體。但是,我們?cè)诖颂幙吹降?code>NumTurns只是一個(gè)聲明式。
通常情況下,C++要求我們對(duì)使用的任何東西都提供一個(gè)定義式,但如果它是個(gè)專屬常量又是static且為整數(shù)類型(本例),則需特殊處理。如果我們是使用時(shí)不取常量的地址,我們可以聲明并使用而無須提供定義式。否則就必須提供如下定義式:

const int GamePlayer::NumTurns;  

上式需要放進(jìn)一個(gè)實(shí)現(xiàn)文件而非頭文件。由于class常量已在聲明時(shí)獲得初值,因此定義時(shí)不可再設(shè)置初值。

2. 使用enum替換#define

剛才的例子:

class GamePlayer {
private:
  static const int NumTurns = 5;  // 常量聲明式
  int scores[NumTurns];
}

有時(shí)候,有的編譯器不允許static成員在其聲明式上獲得初值。所以只能將初值放在定義式:

// 頭文件
class GamePlayer {
private:
  static const int NumTurns = 5;  // 常量聲明式
};
//實(shí)現(xiàn)文件
const int GamePlayer::NumTurns = 5;

但是,類中還有一個(gè)變量int scores[NumTurns],該變量必須在指定NumTurns的值(編譯器要求),這就出現(xiàn)矛盾了。如何解決這個(gè)問題呢,enum hack就出場(chǎng)了!

class GamePlayer{
private:
  enum {NumTurns = 5};
  int scores[NumTurns];
}

我們讓 NumTurns成為5的一個(gè)記號(hào)名稱,這樣就沒問題了。

enum hack的行為某方面說比較像#define而不像const,例如取一個(gè)const的地址是合法的,但取一個(gè)enum的地址就不合法,而取一個(gè)#define的地址也不合法。

3. inline替換#define

有時(shí)候我們會(huì)用#define定義一個(gè)函數(shù):

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

這種寫法有時(shí)會(huì)發(fā)生不可思議的事情:

int a = 10, b = 0;
GET_THE_MAX(++a, b);            // a被累加兩次
GET_THE_MAX(++a, b+20);         // a被累加一次

a的遞增次數(shù)竟然取決于“它被拿來和誰作比較”!
#define定義的宏函數(shù)不會(huì)招致函數(shù)調(diào)用帶來的額外開銷,但是出現(xiàn)這種情況我們也是不希望的。
此時(shí),我們可以使用inline函數(shù)完美解決這個(gè)問題。

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

如果類型不固定為int,可以使用template:

template <typename T> inline T getTheMax(const T&a, const T&b){
    return a > b ? a : b;
}

當(dāng)我們?cè)谡{(diào)用時(shí),

int a = 10, b = 0;
getTheMax(++a, b);            // a被累加一次
getTheMax(++a, b+20);         // a被累加一次

不論與誰作比較,a只會(huì)累加一次。

4.結(jié)語

有了consts, enums和inlines,我們對(duì)預(yù)處理器(特別是#define)的需求降低了,但并非完全消除。#define仍然是必需品,而#ifdef/#ifndef也繼續(xù)扮演控制編譯的重要角色。
對(duì)于#define的使用,需要記住的兩點(diǎn):

  1. 對(duì)于單純變量,最好以const對(duì)象或enum替換#define。
  2. 對(duì)于形似函數(shù)的宏(macros),最好改用inline函數(shù)替換#define。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容