※ 引述《prophet.bbs@cis.nctu.edu.tw (菩提本無樹)》之銘言:
> 請問一下
> int func() const {
> function body
> }
> const 擺在這個位置是什麼意思呢 ?
節錄一段c++ FAQ的中譯……
=============================
■□ 第11節:Const 正確性
=============================
Q45:什麼是 "const correctness"?
好問題。
「常數正確性」乃使用 "const" 關鍵字,以確保常數物件不會被更動到。譬如:若
"f()" 函數接收一個 "String",且 "f()" 想確保 "String" 不會被改變,你可以:
* 傳值呼叫 (pass by value): void f( String s ) { /*...*/ }
* 透過常數參考 (reference): void f(const String& s ) { /*...*/ }
* 透過常數指標 (pointer) : void f(const String* sptr) { /*...*/ }
* 但不能用非常數參考 : void f( String& s ) { /*...*/ }
* 也不能用非常數指標 : void f( String* sptr) { /*...*/ }
在接收 "const String&" 參數的函數裡面,想更動到 "s" 的話,會產生個編譯期的
錯誤;沒有犧牲任何執行期的空間及速度。
宣告 "const" 參數也是另一種型別安全方法,就像一個常數字串,它會“喪失”各
種可能會變更其內容的行為動作。如果你發現型別安全性質讓你的系統正確地運作
(這是真的;特別是大型的系統),你會發現「常數正確性」亦如是。
========================================
Q46:我該早一點還是晚一點讓東西有常數正確性?
越越越早越好。
延後補以常數正確性,會導致雪球效應:每次你在「這兒」用了 "const",你就得在
「那兒」加上四個以上的 "const"。
========================================
Q47:什麼是「const 成員函數」?
一個只檢測(而不更動)其物件的成員函數。
class Fred {
public:
void f() const;
}; // ^^^^^--- 暗示說 "fred.f()" 不會改變到 "fred"
此乃意指:「抽象層次」的(用戶可見的)物件狀態不被改變(而不是許諾:該物件
的「每一個位元內容」都不會被動到)。C++ 編譯器不會對你許諾「每一個位元」這
種事情,因為不是常數的別名(alias)就可能會修改物件的狀態(把 "const" 指標
黏上某個物件,並不能擔保該物件不被改變;它只能擔保該物件不會「被該指標的動
作」所改變)。
【譯註】請逐字細讀上面這句話。
"const" 成員函數常被稱作「查詢子」(inspector),不是 "const" 的成員函數則
稱為「更動子」(mutator)。
========================================
Q48:若我想在 "const" 成員函數內更新一個「看不見的」資料成員,該怎麼做?
使用 "mutable" 或是 "const_cast"。
【譯註】這是很新的 ANSI C++ RTTI (RunTime Type Information) 規定,Borland
C++ 4.0 就率先提供了 const_cast 運算子。
少數的查詢子需要對資料成員做些無害的改變(譬如:"Set" 物件可能想快取它上一
回所查到的東西,以加速下一次的查詢)。此改變「無害」是指:此改變不會由物件
的外部介面察覺出來(否則,該運作行為就該叫做更動子,而非查詢子了)。
這類情況下,會被更動的資料成員就該被標示成 "mutable"(把 "mutable" 關鍵字
放在該資料成員宣告處前面;也就是和你放 "const" 一樣的地方),這會告訴編譯
器:此資料成員允許 const 成員函數改變之。若你不能用 "mutable" 的話,可以用
"const_cast" 把 "this" 的「常數性」給轉型掉。譬如,在 "Set::lookup() const"
裡,你可以說:
Set* self = const_cast<Set*>(this);
這行執行之後,"self" 的位元內容就和 "this" 一樣(譬如:"self==this"),但
是 "self" 是一個 "Set*" 而非 "const Set*" 了,所以你就可以用 "self" 去修改
"this" 指標所指向的物件。
========================================
Q49:"const_cast" 會不會喪失最佳化的可能?
理論上,是;實際上,否。
就算編譯器沒真正做好 "const_cast",欲避免 "const" 成員函數被呼叫時,會造成
暫存器快取區被清空的唯一方法,乃確保沒有任何「非常數」的指標指向該物件。這
種情況很難得會發生(當物件在 const 成員函數被啟用的範圍內被建立出來;當所
有非 const 的成員函數在物件建立間啟用,和 const 成員函數的啟用被靜態繫結住
;當所有的啟用也都是 "inline";當建構子本身就是 "inline";和當建構子所呼叫
的任何成員函數都是 inline 時)。
【譯註】這一段話很難翻得好(好啦好啦!我功力不足... :-< ),所以附上原文:
Even if a compiler outlawed "const_cast", the only way to avoid flushing
the register cache across a "const" member function call would be to
ensure that there are no non-const pointers that alias the object. This
can only happen in rare cases (when the object is constructed in the scope
of the const member fn invocation, and when all the non-const member
function invocations between the object's construction and the const
member fn invocation are statically bound, and when every one of these
invocations is also "inline"d, and when the constructor itself is "inline"d,
and when any member fns the constructor calls are inline).
--
※ Origin: 楓橋驛站<bbs.cs.nthu.edu.tw> ◆ From: Viking.m3.ntu.edu.tw