文章轉載自:http://blog.csdn.net/lihao21/article/details/11715165
在介紹C++
的常量前,先看下下面的代碼。
for (int i = 0; i < 512; ++i) {
…;
}
512
是什么,它具有什么含義?在代碼中若直接使用類似512
這些“魔數”(magic number),這些數字的具體含義就不能體現出來。另外,假如程序中多處包含512
這個數,隨著時間的推移,發現有些512
需要更改為1024
,有些512
需要保持不變。這種情況下,程序員必須小心謹慎地去一個一個地查找程序中所有的512
,并保證更改的數字不會出錯——使用“魔數”會導致難以維護的問題。
為了解決以上問題,可以使用#define
預處理器指令來定義一個常量。例如:
#define MAX_NUM_SIZE 512
for (i = 0; i < MAX_NUM_SIZE; ++i) {
…;
}
通過使用#define
定義MAX_NUM_SIZE
這個宏,可以清晰看到512
的具體含義,另外,假如需要更改這個數字,只須直接修改#define
一處就可以了。
然而,在C++
中,并不提倡使用#define
定義一個常量。#define
本質上是一個預處理器指令,它僅僅表示使用一個串代替別一個串而已。也就是說,#define
定義的常量從未被編譯器看到——它們在編譯器開始處理源碼之前就被移走了。
具體來說,避免使用#define
來定義常量,原因如下所述。
- 沒有指定類型
#define
不涉及為定義的常量做類型檢查,為了顯式地指定常量類型,需要在常量后加上后綴。比如,對于float
類型的常量,在數字后面加上f
后綴。
-
沒有指定作用域
#define
定義的常量是全局的。 沒有訪問控制
不能把#define
定義的常量標記為公有的,受保護的,或者私有的,它本質上是公有的。
因為宏一旦被定義,它就在其后的編譯過程中有效(除非在某處被#undef
)。-
沒有符號
前面的例子中,宏
MAX_NUM_SIZE
可能會被預處理器從代碼中剝離,這樣,編譯器就無法看見這個名字。這樣,程序員在調試時只能看到一些沒有任何描述性的常量值。
與使用#define
定義常量相比,更可取的辦法是使用C++
的const
限定修飾符來定義常量。例如,對于MAX_NUM_SIZE
,可進行如下定義:
const int MAX_NUM_SIZE = 512;
作為一個整型常量,const
修飾的MAX_NUM_SIZE
肯定被編譯器看到,當然會進入符號表。假如將MAX_NUM_SIZE
定義在某個類中,還可以對其實施訪問控制器和為其指定作用域。例如:
class GamePlayer
{
private:
static const int MAX_NUM_SIZE; // static修飾符是為了確保此常量只有一份實體
};
const int GamePlayer:: MAX_NUM_SIZE = 512;
在上述的代碼中,我們定義了一個int
型的常量,該常量的作用域為GamePlayer
類在,并標記為私有訪問,并且會進入符號表。
值得指出的是,要注意const
定義常量在某種程度上可能會使代碼更臃腫。例如,在某個頭文件中定義的了以下的一些常量:
const int MAX_NAME_LENGTH = 128;
const float LOG_2E = log2(2.71828183f);
const std::string LOG_FILE_NAME = “filename.log”;
在默認情況下,以這種方式定義的變量會促使編譯器為每個包含此頭文件的模塊分配變量存儲空間。如果定義了很多常量,并且該頭文件被很多.cpp
文件包含,那么會導致.o
目標文件和最終的二進制文件膨脹。
解決辦法是在頭文件中使用extern
聲明常量:
// myconst.h
extern const int MAX_NAME_LENGTH;
extern const float LOG_2E;
extern const std::string LOG_FILE_NAME;
然后在相應的.cpp
文件中定義每個常量的值:
// myconst.cpp
const int MAX_NAME_LENGTH = 128;
const float LOG_2E = log2(2.71828183f);
const std::string LOG_FILE_NAME = “filename.log”;
通過這種方式,變量的空間就只會分配一次。
使用extern
來聲明的常量是全局的,若要將常量的作用域限制在類中,則須在類中聲明常量,并將其聲明為static
(這樣它們就不會計入每個對象的內存大小中)。
// myclass.h
class MyClass
{
public:
static const int MAX_NAME_LENGTH;
static const float LOG_2E;
static const std::string LOG_FILE_NAME;
};
然后在相應的.cpp
文件中定義這些常量:
// myclass.cpp
const int MAX_NAME_LENGTH = 128;
const float LOG_2E = log2(2.71828183f);
const std::string LOG_FILE_NAME = “filename.log”;
當然,在某些情況下,使用枚舉類型代替常量也可以避免文件空間膨脹的問題。
參考資料:
- C++ Primer 中文版,第三版
- C++ API 設計
- Effective C++ 中文版,第三版