const 是constant 的縮寫,是恒定不變的意思,也翻譯為常量、常數等。很不幸,正是因為這一點,很多人都認為被const 修飾的值是常量。這是不精確的,精確的說應該是只讀的變量,其值在編譯時不能被使用,因為編譯器在編譯時不知道其存儲的內容。或許當初這個關鍵字應該被替換為readonly。那么這個關鍵字有什么用處和意義呢?
const 推出的初始目的,正是為了取代預編譯指令,消除它的缺點,同時繼承它的優點。我們看看它與define 宏的區別。(很多人誤以為define 是關鍵字,在這里我提醒你再回到本章前面看看32 個關鍵字里是否有define)。
? ?const intMax=100;
? ?intArray[Max];
這里請在Visual C++6.0 里分別創建.c 文件和.cpp 文件測試一下。你會發現在.c 文件中,編譯器會提示出錯,而在.cpp 文件中則順利運行。為什么呢?我們知道定義一個數組必須指定其元素的個數。這也從側面證實在C 語言中,const 修飾的Max 仍然是變量,只不過是只讀屬性罷了;而在C++里,擴展了const 的含義,這里就不討論了。
注意:const 修飾的只讀變量必須在定義的同時初始化,想想為什么?
留一個問題:case 語句后面是否可以是const 修飾的只讀變量呢?請動手測試一下。
? ?#define M 3 //宏常量
? ?const int N=5; //此時并未將N 放入內存中
? ?......
? ?int i=N; //此時為N 分配內存,以后不再分配!
? ?int I=M; //預編譯期間進行宏替換,分配內存
? ?int j=N; //沒有內存分配
? ?int J=M; //再進行宏替換,又一次分配內存!
const 定義的只讀變量從匯編的角度來看,只是給出了對應的內存地址,而不是象#define一樣給出的是立即數,所以,const 定義的只讀變量在程序運行過程中只有一份拷貝(因為它是全局的只讀變量,存放在靜態區),而#define 定義的宏常量在內存中有若干個拷貝。
#define 宏是在預編譯階段進行替換,而const 修飾的只讀變量是在編譯的時候確定其值。
#define 宏沒有類型,而const 修飾的只讀變量具有特定的類型。
? ?int const i=2; 或const int i=2;
? ?int const a[5]={1, 2, 3, 4, 5};或
? ?const int a[5]={1, 2, 3, 4, 5};
? ?int const *p; // p 可變,p 指向的對象不可變
? ?int *const p; // p 不可變,p 指向的對象可變
? ?const int *const p; //指針p 和p 指向的對象都不可變
在平時的授課中發現學生很難記住這幾種情況。 這里給出一個記憶和理解的方法:先忽略類型名(編譯器解析的時候也是忽略類型名),我們看const 離哪個近。“近水樓臺先得月”,離誰近就修飾誰。
? ?const int *p; //const 修飾*p,p 是指針,*p 是指針指向的對象,不可變
? ?int const *p; //const修飾*p,p 是指針,*p 是指針指向的對象,不可變
? ?int *const p; //const修飾p,p 不可變,p 指向的對象可變
? ?const int *const p; //前一個const 修飾*p,后一個const 修飾p,指針p 和p 指向的對象都不可變
? ?void Fun(const int i);
告訴編譯器i 在函數體中的不能改變,從而防止了使用者的一些無意的或錯誤的修改。
? ?const int Fun (void);
在另一連接文件中引用const 只讀變量:
? ?extern const int i; //正確的聲明
? ?extern const int j=10; //錯誤!只讀變量的值不能改變。
注意這里是聲明不是定義,關于聲明和定義的區別,請看本章開始處。
講了這么多講完了嗎?遠沒有。在C++里,對const 做了進一步的擴展,還有很多知識未能講完。有興趣的話,不妨查找相關資料研究研究。
const 推出的初始目的,正是為了取代預編譯指令,消除它的缺點,同時繼承它的優點。我們看看它與define 宏的區別。(很多人誤以為define 是關鍵字,在這里我提醒你再回到本章前面看看32 個關鍵字里是否有define)。
一、const 修飾的只讀變量
定義const 只讀變量,具有不可變性。例如:? ?const intMax=100;
? ?intArray[Max];
這里請在Visual C++6.0 里分別創建.c 文件和.cpp 文件測試一下。你會發現在.c 文件中,編譯器會提示出錯,而在.cpp 文件中則順利運行。為什么呢?我們知道定義一個數組必須指定其元素的個數。這也從側面證實在C 語言中,const 修飾的Max 仍然是變量,只不過是只讀屬性罷了;而在C++里,擴展了const 的含義,這里就不討論了。
注意:const 修飾的只讀變量必須在定義的同時初始化,想想為什么?
留一個問題:case 語句后面是否可以是const 修飾的只讀變量呢?請動手測試一下。
二、節省空間,避免不必要的內存分配,同時提高效率
編譯器通常不為普通const 只讀變量分配存儲空間,而是將它們保存在符號表中,這使得它成為一個編譯期間的值,沒有了存儲與讀內存的操作,使得它的效率也很高。例如:? ?#define M 3 //宏常量
? ?const int N=5; //此時并未將N 放入內存中
? ?......
? ?int i=N; //此時為N 分配內存,以后不再分配!
? ?int I=M; //預編譯期間進行宏替換,分配內存
? ?int j=N; //沒有內存分配
? ?int J=M; //再進行宏替換,又一次分配內存!
const 定義的只讀變量從匯編的角度來看,只是給出了對應的內存地址,而不是象#define一樣給出的是立即數,所以,const 定義的只讀變量在程序運行過程中只有一份拷貝(因為它是全局的只讀變量,存放在靜態區),而#define 定義的宏常量在內存中有若干個拷貝。
#define 宏是在預編譯階段進行替換,而const 修飾的只讀變量是在編譯的時候確定其值。
#define 宏沒有類型,而const 修飾的只讀變量具有特定的類型。
三、修飾一般變量
一般常量是指簡單類型的只讀變量。這種只讀變量在定義時,修飾符const 可以用在類型說明符前,也可以用在類型說明符后。例如:? ?int const i=2; 或const int i=2;
四、修飾數組
定義或說明一個只讀數組可采用如下格式:? ?int const a[5]={1, 2, 3, 4, 5};或
? ?const int a[5]={1, 2, 3, 4, 5};
五、修飾指針
? ?const int *p; // p 可變,p 指向的對象不可變? ?int const *p; // p 可變,p 指向的對象不可變
? ?int *const p; // p 不可變,p 指向的對象可變
? ?const int *const p; //指針p 和p 指向的對象都不可變
在平時的授課中發現學生很難記住這幾種情況。 這里給出一個記憶和理解的方法:先忽略類型名(編譯器解析的時候也是忽略類型名),我們看const 離哪個近。“近水樓臺先得月”,離誰近就修飾誰。
? ?const int *p; //const 修飾*p,p 是指針,*p 是指針指向的對象,不可變
? ?int const *p; //const修飾*p,p 是指針,*p 是指針指向的對象,不可變
? ?int *const p; //const修飾p,p 不可變,p 指向的對象可變
? ?const int *const p; //前一個const 修飾*p,后一個const 修飾p,指針p 和p 指向的對象都不可變
六、修飾函數的參數
const 修飾符也可以修飾函數的參數,當不希望這個參數值被函數體內意外改變時使用。例如:? ?void Fun(const int i);
告訴編譯器i 在函數體中的不能改變,從而防止了使用者的一些無意的或錯誤的修改。
七、修飾函數的返回值
const 修飾符也可以修飾函數的返回值,返回值不可被改變。例如:? ?const int Fun (void);
在另一連接文件中引用const 只讀變量:
? ?extern const int i; //正確的聲明
? ?extern const int j=10; //錯誤!只讀變量的值不能改變。
注意這里是聲明不是定義,關于聲明和定義的區別,請看本章開始處。
講了這么多講完了嗎?遠沒有。在C++里,對const 做了進一步的擴展,還有很多知識未能講完。有興趣的話,不妨查找相關資料研究研究。