類定義裏面,可以看到類似下面的定義:
07 |
int GetLength
() const ; |
08 |
bool GetNodeInfo( const int index,Node
& buffer) const {……
} |
09 |
bool DeleteNode( const int index); |
可以看到,在GetLength和GetNodeInfo兩個成員函數的參數列表後面出現了一個const。這個const指明瞭這個函數不會修改該類的任何成員數據的值,稱爲常量成員函數。
對於const函數的外部定義,也不能忘記書寫const限定符,如下面給出GetLength函數(指返回鏈表的長度)的定義:
1 |
int List::GetLength() const |
如果在const成員函數的定義中出現了任何修改對象成員數據的現象,都會在編譯時被檢查出來,如:
1 |
int List::GetLength() const |
const成員函數存在的意義在於它能被const常對象調用。我們都知道,在定義一個對象或者一個變量時,如果在類型前加一個const,如const int x;,則表示定義的量爲一個常量,它的值不能被修改。但是創建的對象卻可以調用成員函數,調用的成員函數很有可能改變對象的值,比如下面這段程序:
顯然調用DeleteNode這個成員函數刪除一個鏈表結點後,很有可能改變對象中length(鏈表長度)這個值,這不符合const對象的規定。但是,如果不允許const對象調用任何成員函數又是非常不合理的。於是,我們把那些肯定不會修改對象的各個屬性值的成員函數加上const說明符,這樣,在編譯時,編譯器將對這些const成員函數進行檢查,如果確實沒有修改對象值的行爲,則檢驗通過。以後,如果一個const常對象調用這些const成員函數的時候,編譯器將會允許。比如:
你可能會問,爲什麼不在一個const常對象調用成員函數的時候再進行檢查呢?如果被調用的函數會改變對象的屬性值,則立即打住就是了。這樣就不用麻煩地在成員函數後面加const限定符了。然而,這無疑會大大增加編譯時間。考慮下面這段代碼:
這段代碼中,GetLength被調用了兩次,但是編譯時卻也要檢查兩次,倘使一個成員函數被調用多次,那麼他將在每次調用的時候都會被檢查。這顯然大大不利。而如果在定義類的時候加上const限定符對常函數加以標記,那麼編譯器只是檢查一次就好,在const對象調用成員函數時,const函數將會被直接放行。所以,C++採取了const限定符描述常函數方案而擯棄了後者。所以,即使一個函數沒有修改對象值的行爲,如果沒有加上const限定符說明是常函數,那麼const對象依然不能調用它。
然而,有些時候,我們卻必須要讓const函數具有修改某個成員數據值的能力。比如一些內部的狀態量,對外部用戶無所謂,但是對整個對象的運行卻大有用處,如支持緩存的技術。遇到這種問題,我們可以把一個成員數據定義爲mutable(多變的),它表示這個成員變量可以被const成員函數修改卻不違法。比如下面定義了一個is_valid類成員:
05 |
mutable bool is_valid; |
08 |
bool CheckList() const |
10 |
if (length
>= 1) then return is_valid
= true ; |
11 |
else return is_valid
= false ; |
這樣,即使像CheckList這樣的const成員函數修改它也是合法的。
但需要注意的時,不可濫用mutabe描述符,如果在某個類中只有少數一部分是被允許const常量函數修改的,使用mutable是再合適不過的。如果大部分數據都定義爲mutable,那麼最好將這些需要修改的數據放入另一個獨立的對象裏,並間接地訪問它。
參考資料:《C++ Programming Language 第三版》
注:本文屬知無涯原創,轉載請註明出處!