《Effective C++》讀書筆記 條款02 盡量以const,enum,inline替換#define
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