#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