Effective c++(01,02)
條款一:
視C++為一個語言聯邦
條款二:
儘量以const、enum、inline替換#define
1、你所使用的名稱可能並未進入記號表,從而帶來一些編碼和理解上的困惑。
#define ASPECT_RATIO 1.635
記號名ASPECT_RATIO可能從未被編譯器看到;也許在編譯器開始處理原始碼之前他就被前處理器移走了,於是記號名稱ASPECT_RATIO從未進入記號表內。如果發生錯誤,可能錯誤資訊會提到1.635而不是ASPECT_RATIO。如果剛好ASPECT_RATIO是在一個非你本人所寫的標頭檔案中,需要浪費時間跟蹤。
解決方法就是以一個常量替代巨集
const double ASPECT_RATIO = 1.635;
常量替換巨集有兩種特殊的情況:定義常量指標和class專屬常量。為了將常量的作用域限制於class內,必須讓它成為class的一個成員;而為了確保此常量至多隻有一份實體,必須讓它成為一個static成員。
2、無法利用#define建立一個class專屬常量,因為#define並不重視作用域。一旦巨集被定義,它就在其後的編譯過程中有效(除非在某處被#undef)。這意味著#define不僅不能用來定義class的專屬常量,也不能提供任何封裝性,即沒有private屬性。而const可以。
3、認識enum hack
enum hack的行為更像#define而不是const,如果你不希望別人得到你的常量成員的指標或引用,你可以用enum hack替代之。(為什麼不直接用#define呢?首先,因為#define是字串替換,所以不利於程式除錯。其次,#define的可視範圍難以控制,比如你怎麼讓#define定義的常量只在一個類內可見呢?除非你用醜陋的#undef);
使用enum hack不會導致 “不必要的記憶體分配”;
enum hack是模板超程式設計的一項基本技術,大量的程式碼在使用它。當你看到它時,你要認識它;
class Game {
private:
// static const int GameTurn;
enum {GameTurn = 10};
int scores[GameTurn];
};
上述陣列的宣告就是利用enum hack實現。
remember
對於單純常量,最好以const物件或enum替換#defines;
對於形似函式的巨集(macros),最好改用inline函式替換#defines
TIPS
1、靜態常量資料成員可以在類內初始化(即類內宣告的同時初始化),也可以在類外,即類的實現檔案中初始化,不能在建構函式中初始化,也不能在建構函式的初始化列表中初始化。通常c++要求對所使用的東西提供一個定義式,但如果它是一個class專屬常量有事static且為整數型別(例如int, char,bool),則需特殊處理。只要不取它們的地址,可以生命並使用它們而無需提供定義式。但如果需要使用他們的地址或者編譯器堅持需要看到一個定義式,就需要在類外提供定義式,而此時不用再賦初值;
2、靜態非常量資料成員只能且必須在類外,即類的實現檔案中初始化;
3、非靜態的常量資料成員只能且必須在建構函式的初始化列表中初始化;
4、非靜態的非常量資料成員不能在類內初始化,可以在建構函式中初始化,也可以在建構函式的初始化列表中初始化
總結一下(為了避免出錯且方便記憶):
非靜態的量,在建構函式的初始化列表中初始化;
靜態量,在類外,即類的實現檔案中初始化。