被const修飾的函數
標籤(空格分隔):c/c++
部分參考:http://www.tuicool.com/articles/Nz6N3e
用const修飾函數的參數
如果輸入參數採用
指針傳遞
,那麼加 const 修飾可以防止意外地改動該指針,起到保護作用。
例如 StringCopy 函數:void StringCopy(char *destination, const char *source);
如果輸入參數採用“值傳遞”,由於函數將自動產生臨時變量用於複製該參數,則輸入參數無需保護,所以不要加 const 修飾,即不是所有的入參都需要進行const保護。
【一種特殊的情況】
即對於非內部數據類型的參數而言,像 void func(A a) 這樣聲明的函數註定效率比較低。因爲函數體內將產生A類型的臨時對象用於複製參數a,而臨時對象的構造、複製、析構過程都將消耗時間。爲了提高效率,可以將函數聲明改爲 void func(A &a),因爲“引用傳遞”僅借用一下參數的別名而已,不需要產生臨時對象。但是函數 void func(A &a) 存在一個缺點:“引用傳遞”有可能改變參數a,這是我們不期望的。解決這個問題很容易,加const修飾即可,因此函數最終成爲 void func(const A &a)。
那麼問題來了:是否應將 void func(int x) 改寫爲 void func(const int &x),以便提高效率?完全沒有必要,因爲內部數據類型的參數不存在構造、析構的過程,而複製也非常快,“值傳遞”和“引用傳遞”的效率幾乎相當。
【總結一下】
(1)對於非內部數據類型的輸入參數,應該將“值傳遞”的方式改爲“const 引用傳遞”,目的是提高效率。例如將 void func(A a) 改爲 void func(const A &a)。
(2)對於內部數據類型的輸入參數,不要將“值傳遞”的方式改爲“const 引用傳遞”。否則既達不到提高效率的目的,又降低了函數的可理解性。例如 void func(int x) 不應該改爲void func(const int &x)。用const 修飾函數的返回值
如果給以“指針傳遞”方式(返回值)的函數返回值加 const 修飾,那麼函數返回值(即指針)的內容不能被修改, 該返回值只能被賦給加 const 修飾的同類型指針。如下語句將出現編譯錯誤:
char *str = getString();
正確的用法是:
const char *str = getString();
如果函數返回值採用“值傳遞方式”,由於函數會把返回值複製到外部臨時的存儲單元中,加const 修飾沒有任何價值。例如,不要把函數 int getInt(void) 寫成 const int getInt(void)。同理不要把函數 A getA(void) 寫成 const A getA(void),其中 A 爲用戶自定義的數據類型。
如果返回值不是內部數據類型,將函數 A getA(void) 改寫爲 const A & getA(void) 的確能提高效率。但此時千萬千萬要小心,一定要搞清楚函數究竟是想返回一個對象的“拷貝”還是僅返回“別名”就可以了,否則程序會出錯。
const 成員函數
任何不會修改數據成員的函數都應該聲明爲 const 類型。
在類中,const關鍵字位於函數名之後的位置(注意寫法),比如:class classname{ ... int GetCount(void) const; // const 成員函數 ... };
總結
關於 const 函數的幾點規則:
- const 對象只能訪問 const 成員函數(類似於類的靜態成員函數),而非 const 對象可以訪問任意的成員函數,包括 const 成員函數。
- const 對象的成員是不可修改的,然而 const 對象通過指針維護的對象(指針對象作爲成員)卻是可以修改的。
- const 成員函數不可以修改對象的數據,不管對象是否具有 const 性質。它在編譯時,以是否修改成員數據爲依據,進行檢查。
- 然而加上 mutable 修飾符的數據成員,對於任何情況下通過任何手段都可修改,自然此時的 const 成員函數是可以修改它的。
【解釋:爲什麼const對象只能訪問const成員函數】
當我們的對象是const對象時,比如const CTest ttt;
這時候表示什麼意思呢?ttt的內容是不可以改變的,當我們把&ttt作爲一個參數傳到形參this時,矛盾出現了:(1)ttt的成員不可以被改變。(2)this指針的成員變量是可以改變的(只是this指向的對象地址不能改變)。如果我能正確的將ttt的地址傳給this,那麼ttt這個常量的值就可以在this中被改變了!,所以,編譯器是不允許這種情況出現的,也就是說如果我們用const對象訪問了非const成員函數就提示錯誤了。故,const對象不能訪問非const成員函數。
當我們的成員函數是const成員函數時,例:CTest::ttt() const;
,在編譯器解釋時會將該函數解釋爲CTest::ttt(const CTest const this)
,this指針及其所指向的內容都不可以被修改,前面提到的矛盾也就不存在了,所以const對象可以訪問const成員變量。【const成員函數的訪問權限】
a. const成員函數不被允許修改它所在對象的任何一個數據成員。
b. const成員函數能夠訪問對象的const成員,而其他成員函數不可以。
補充
使用const的優點之節省空間、提高效率
【節省空間】const定義常量從彙編的角度來看,只是給出了對應的內存地址,而不是象#define一樣給出的是立即數,所以,const定義的常量在程序運行過程中只有一份拷貝,而#define定義的常量在內存中有若干個拷貝。
【提高效率】編譯器通常不爲普通const常量分配存儲空間,而是將它們保存在符號表中,這使得它成爲一個編譯期間的常量,沒有了存儲與讀內存的操作,使得它的效率也很高。const修飾成員變量
const修飾類的成員,表示成員常量,不能被修改,同時它只能在初始化列表中賦值。將const類型轉化爲非const類型的方法
採用const_cast 進行轉換。
用法:const_cast <type_id> (expression)
其他補充
如果在非const成員函數中,this指針只是一個類類型的;如果在const成員函數中,this指針是一個const類類型的(底層的const,this本身是默認頂層的const);如果在volatile成員函數中,this指針就是一個volatile類類型的。
new返回的指針必須是const類型的。