天天看點

筆記:Perfer consts,enums,and inlines to #define

 #define 或許不被視為語言的一部分。

#define ASPECT_RATIO 1.63

ASPECT_RATIO也許從未被編譯器看見,也許在編譯器開始處理源碼之前就被預處理器移走了。

于是ASPECT_RATIO有可能沒有進入符号表(symbol table).

要是出現錯誤就不好調試。

可能出現兩個錯誤,錯誤資訊說1.63而不是ASPECT_RATIO。或者這個定義出現在另外的頭檔案,出現這個錯誤可能在符号調試器中(symbolic debugger),但是因為ASPECT_RATIO不在符号表中出現錯誤。

解決的辦法是用常量代替上述的宏(#define)

const double AspectRatio = 1.63           

//大寫名稱通常用于宏,這裡是變量。

作為一個常量,AspectRatio肯定會被編譯器看見,也就會進入符号表内。

此外對浮點常量(floating point constant)而言,使用常量可能比使用#define導緻較小量的碼,因為預處理會盲目将宏ASPECT_RATIO替換成1.63,導緻目标碼(object code)出現多份1.63,若改用常量就不會出現這樣的情況。

當使用常量替換#define,有兩種特殊的情況.

1,定義常量指針(constant pointers)

由于常量定義式通常被放在頭檔案内讓不同的源代碼使用,是以有必要對指針(不僅僅是指針所指向的對象)聲明為const。(防止被改動)

例如若要在頭檔案定義一個常量的基于char*的字元串,必須寫const兩次:

const char* const authorName = "Scott Meyers";

關于const的意義和使用(特别是與指針結合時),在條款3有詳細的讨論。

string對象通常比char*-based 合适,是以下面定義更好:

const std::string authorName= "Scott Meyers";

2,class專屬常量。

若要使某個常量的作用域(scope)限制于class内,必須讓它成為class的一個成員。

若是要使這個常量隻有一份實體,就必須讓其是static成員。

class GamePlayer

{

private:

 static const int NumTurns = 5;   //這個表達式是常量聲明式,非定義式。

 int scores[NumTurns];    // 使用了該常量

 。。。

};

C++要求你對你所使用的任何變量都提供一個定義式,如果它是class的專屬常量,還是static的,并且類型為整數類型(integral type,例如int,char,bool),要特殊處理。隻要不取他們的位址,可以隻聲明并且使用而不需要再提供一個定義式。

若是要取class專屬常量的位址就必須提供一個定義式

const int GamePlayer::NumTurns;           //NumTurns的定義式。為什麼沒有指派了?

這個定義式放在CPP檔案中,由于class常量在聲明時候已經獲得初值,是以定義時不需要再設初值。

在VS 2005中要是提供了定義式則會出現重複定義的錯誤。

用G++編譯器則是對的。

不過一般舊的編譯器也是不支援以上的文法,不允許static成員在其聲明式上獲得初值。則隻有把初值放在定義式中。

比如

class CostEstimate

{

private:

static const double FudgeFactor;   //static const  常量聲明 位于頭檔案

};

const double CostEstimate::FudgeFactor = 2.33;          //static const 常量定義位于實作檔案内(cpp檔案)

再就是在類中(in-class)的初值設定也隻允許對整數常量進行,其他的資料類型必須在定義式中進行賦初值。

有一種例外就是當class編譯期間需要一個class的常量值,就需要一種補償的做法。

比如說class GamePlayer中的score的數組聲明式中必須要知道其大小。編譯器不允許static整數型class常量 完成的在類中的初值設定,就可以改用“the enum hack”補償做法。

這個的理論基礎是:“一個屬于枚舉類型的數值可以權充int被使用”,于是GamePlayer可以定義如下:

class GamePlayer

{

private:

    enum {NumTurns = 5};             //the enum hack  --- 令NumTurns成為5的一個記号名稱

 int scores[NumTurns];    

 。。。

};

基于一些理由enum hack值得我們了解。

1, enum hack的行為某方面比較像 #define而不像 const,有時候這樣就是你所想要的。取const的位址是合法,去enum就不合法。如果你不想别人活着一個指針或引用指向你的某個整數變量,enum是個好的選擇,實作了這個限制。(條款18講解了“通過撰寫代碼來實施設計上的限制條件”)。

2,Effective C++上說是為了實用主義。許多代碼用了它,是以應該了解。 事實上“enum hack”是template metaprogramming(模闆元程式設計,48)的基礎技術。

最後用inline代替宏函數。(條款30詳細說明inline函數)

記住:

1,對于單純常量,最好以const對象活着enum替換 #define

2,對于形似函數的宏,最好改用inline函數替換 #difine

繼續閱讀