1. 程式人生 > >《Effective C++》讀書筆記 條款02 盡量以const,enum,inline替換#define

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

之前 不同的 可執行 effective play fec b+ num mtu

Effective C++在此條款中總結出兩個結論

1.對於單純常量,最好以const對象或enum替換#define

2.對於形似函數的宏,最好改用inline函數替換#define

接下來我們進行詳細的探討。

const替換#define的討論

例如:

#define ASPECT_RATIO 1.653

原書給出的解釋大意是:

你所使用的名稱(ASPECT_RATIO)可能並未進入記號表(symbol table),原因也許是記號名稱ASPECT_RATIO從未被編譯器看見,也許在編譯器開始處理源碼之前他就被預處理器移走了。從而導致一個後果:當你運用此常量但獲得一個編譯錯誤信息時,這個信息也許會提到1.653而不是ASPECT_RATIO(因為所有的ASPECT_RATIO都被1.653代替),使得debug出現困難,因為你可能對1.653來自何處毫無概念,特別在多個文件都定義了ASPECT_RATIO時,無法確定是哪一個常量出了問題。

記號表:每個可重定位目標模塊都有一個符號表,它包含m所定義和引用的符號的信息,在鏈接器的上下文中,有三種不同的符號: 1.由m定義並能被其他模塊引用的全局符號 2.由其他模塊定義並被模塊m引用的全局符號 3.只被模塊m定義和引用的本地符號
可重定位目標文件:     包含二進制代碼和數據,其形式可以在編譯時與其他可重定義目標文件合並起來,創建一個可執行目標文件。 

解決之道是以一個常量替換上述的宏:

const double AspectRatio = 1.653;
作為一個語言常量,AspectRatio肯定會被編譯器看到,當然會進入記號表內。此外對浮點常量而言,使用常量可能比使用#define導致較小量的碼,因為預處理器盲目將宏名稱替換為1.653,可能導致目標碼(object code)出現多份1.653,若改用常量絕不會出現相同情況。

以常量替換#define,有兩種特殊情況值得註意:

1.定義常量指針。若要在頭文件內定義一個指向常量的常量指針,需要些const兩次

        const char* const pc = "c++";//指向常量字符串的常量char*型指針

一個小知識點是,string對象比char*類型的指針更合意,所以pc定義成下面的樣式更好些

        const std::string pc("c++");//常量string對象

2.class類內的專屬常量,為保證至多只有一個實體,必須聲明為static。

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

對於static類型的class專屬常量,若它是整數類(例如int,char,bool),只要不取他們的地址,可以聲明並使用它們而無須提供定義式。

如果必須用到定義式,必須在實現文件而不是頭文件如下定義

const int GamePlayer::NumTurns;//NumTurns的定義

由於NumTurns已在聲明時獲得初值,因此定義時不可以再設初值。如果你的編譯器不支持static成員在其聲明式上獲得初值,可以將初值放在定義式。

static const int NumTurns;//聲明 const int GamePalyer::NumTurns = 5;//定義


以enum替換#define的討論

當你在class編譯期間需要一個class常量值,如果你的編譯器不允許static整數型class常量完成類內初值設定,可使用enum。

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

這樣做的好處是enum不允許取地址,有時這正是我們想要的。如果不想讓別人獲得一個pointer或reference指向你的整數常量,enum可以幫助實現這個約束。

inline替換#define的討論

#define CALL_WITH_MAX(a,b) f((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<tyoename T> inline void callWithMax(cosnt T& a,cosnt T& b) {     f(a > b ? a : b); }

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