關鍵字 mutable 是一個奇怪的修飾符(specifier),它只能夠用於一個類的非待用資料成員。下面我將討論 mutable 的語義和用法,但是首先我要解釋一下 C++ 物件模型的一個關鍵概念。
對象的狀態
一個對象的狀態由其非待用資料成員的值構成,因此,修改一個資料成員將會改變整個對象的狀態。將一個成員函式宣告為 const 能夠保證它不會改變對象的狀態。
然而在一些情況下,對象的邏輯狀態與基物理狀態之間可能有差別。例如,對於一個表示繪畫映像的對象就存在這種情況。如果映像還沒有更改,那麼我們就認為其狀態沒有發生變化。然而,從底層實現方面來說,如果大對象在一段時間沒有活動,那麼它們的記憶體通常會被交換到一個檔案中。交換一個映像並不會真地影響其狀態,但是對象的一些資料成員可能會發生變化,在這裡可能會發生變化的是指標、標誌位等。
在使用者調用一個諸如 Redraw() 之類的 const 成員函數時,他們並不關心這個函數在內部是如何?的。從他們的角度來說,這個函數並不改變對象的邏輯狀態,因此被聲明為 const。Redraw() 有可能修改對象的物理狀態這一事實是一個他們不應該關心的實現細節。例如:
int Image::Redraw() const
{
if (isLoaded==false)
{
//..read image data from a disk into a local buffer
isLoaded=true; //changing a data member's value
}
//..paint image in the screen
}
class Image
可變(mutable)資料成員
如果嘗試編譯這段代碼,你會得到一個編譯錯誤。雖然 Redraw() 聲明為 const,但是它修改了一個資料成員。解決這個編譯錯誤的方法是將 isLoaded 聲明為一個 mutable 資料成員:
class Image
{
public:
int Redraw() const;
//..
private:
mutable bool isLoaded;//can be changed by a const function
};
不像普通的資料成員,const 成員函數可以修改 mutable 資料成員。
Mutable 資料成員的使用看上去像是騙術,因為它能夠使 const 函數修改對象的資料成員。然而,明智地使用 mutable 關鍵字可以提高代碼品質,因為它能夠讓你向使用者隱藏實現細節,而無須使用不確定的東西,比如 const_cast<>。
本文作者:Danny Kalev 是一位系統分析員、軟體工程師,他具有14年在 C++ 和物件導向設計方面的經驗。