【轉(zhuǎn)】http://www.builder.com.cn/2004/0531/119655.shtmlhttp://www.ieee.org.cn/dispbbs.asp?boardID=61&ID=43781關(guān)鍵字 mutable 是一個奇怪的修飾符(specifier),它只能夠用于一個類的非靜態(tài)數(shù)據(jù)成員。下面我將討論 mutable 的語義和用法,但是首先我要解釋一下 C++ 對象模型的一個關(guān)鍵概念
對象的狀態(tài)
一個對象的狀態(tài)由其非靜態(tài)數(shù)據(jù)成員的值構(gòu)成,因此,修改一個數(shù)據(jù)成員將會改變整個對象的狀態(tài)。將一個成員函數(shù)聲明為 const 能夠保證它不會改變對象的狀態(tài)。
然而在一些情況下,對象的邏輯狀態(tài)與基物理狀態(tài)之間可能有差別。例如,對于一個表示繪畫圖像的對象就存在這種情況。如果圖像還沒有更改,那么我們就認(rèn)為其狀態(tài)沒有發(fā)生變化。然而,從底層實(shí)現(xiàn)方面來說,如果大對象在一段時間沒有活動,那么它們的內(nèi)存通常會被交換到一個文件中。交換一個圖像并不會真地影響其狀態(tài),但是對象的一些數(shù)據(jù)成員可能會發(fā)生變化,在這里可能會發(fā)生變化的是指針、標(biāo)志位等。
在用戶調(diào)用一個諸如 Redraw() 之類的 const 成員函數(shù)時,他們并不關(guān)心這個函數(shù)在內(nèi)部是如何實(shí)現(xiàn)的。從他們的角度來說,這個函數(shù)并不改變對象的邏輯狀態(tài),因此被聲明為 const。Redraw() 有可能修改對象的物理狀態(tài)這一事實(shí)是一個他們不應(yīng)該關(guān)心的實(shí)現(xiàn)細(xì)節(jié)。例如:
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)數(shù)據(jù)成員
如果嘗試編譯這段代碼,你會得到一個編譯錯誤。雖然 Redraw() 聲明為 const,但是它修改了一個數(shù)據(jù)成員。解決這個編譯錯誤的方法是將 isLoaded 聲明為一個 mutable 數(shù)據(jù)成員:
class Image
{
public:
int Redraw() const;
//..
private:
mutable bool isLoaded;//can be changed by a const function
};
不像普通的數(shù)據(jù)成員,const 成員函數(shù)可以修改 mutable 數(shù)據(jù)成員。
Mutable 數(shù)據(jù)成員的使用看上去像是騙術(shù),因?yàn)樗軌蚴?const 函數(shù)修改對象的數(shù)據(jù)成員。然而,明智地使用 mutable 關(guān)鍵字可以提高代碼質(zhì)量,因?yàn)樗軌蜃屇阆蛴脩綦[藏實(shí)現(xiàn)細(xì)節(jié),而無須使用不確定的東西,比如 const_cast<>。
具體一些的例子:
mutable的作用是用來修飾類的成員變量,使這個成員變量的值在任何情況下都可以被修改,例如:
為敘述方便,預(yù)定義一個類TObject,如下:
class TObject
{
int iValue;
};
情況1:
我們知道,若TObject中存在一個成員函數(shù),并且次函數(shù)的聲明末尾加上了const關(guān)鍵字,形式如下:
void setValue(int) const; // 注:有些地方把這種函數(shù)稱為常函數(shù)。
那么這就意味著,這個函數(shù)的實(shí)現(xiàn)中不能修改該類的成員變量的值,但是,倘若我們要記錄這個函數(shù)調(diào)用的次數(shù),我們會有很多方法,如間接調(diào)用該函數(shù),但是這顯然不是一個好方法,這會增加類的復(fù)雜度。這個時候mutable就派上用場了,它可以使被修飾的成員變量在該種情況下被改變,你可以這樣書寫代碼:
class TObject
{
mutable int iValue;
public:
void setValue(int pValue) const
{
iValue++;
}
};
當(dāng)然,這并不是一個好例子,因?yàn)樗鼪]有多少實(shí)用價(jià)值,我的目的在于說明問題。
情況2:
若有一個TObject的實(shí)例被定義為常量,如:
const TObject tObject; // 注:有些地方將之稱為常對象。
如果沒有mutable的話,這顯然意味著你將無法修改該對象,那么,如果你只希望關(guān)閉掉部分成員變量的修改權(quán),那么你就應(yīng)該像情況1那么書寫代碼,讓你調(diào)用setValue成員函數(shù)時仍能修改iValue的值。