只要一聽到被面試者說:"const意味着常數"(不是常數,可以是變量,只是你不能修改它),我就知道我正在和一個業餘者打交道。去年Dan Saks已經在他的文章裏完全概括了const的所有用法,因此ESP(譯者:Embedded Systems Programming)的每一位讀者應該非常熟悉const能做什麼和不能做什麼.如果你從沒有讀到那篇文章,只要能說出const意味着"只讀"就可以了。儘管這個答案不是完全的答案,但我接受它作爲一個正確的答案。(如果你想知道更詳細的答案,仔細讀一下Saks的文章吧。)
如果應試者能正確回答這個問題,我將問他一個附加的問題:下面的聲明都是什麼意思?
Const只是一個修飾符,不管怎麼樣a仍然是一個int型的變量
const int a;
int const a;
const int *a;
int * const a;
int const * a const;
本質:const在誰後面誰就不可修改,const在最前面則將其後移一位即可,二者等效
前兩個的作用是一樣,a是一個常整型數。第三個意味着a是一個指向常整型數的指針(也就是,指向的整型數是不可修改的,但指針可以,此最常見於函數的參數,當你只引用傳進來指針所指向的值時應該加上const修飾符,程序中修改編譯就不通過,可以減少程序的bug)。
第四個意思a是一個指向整型數的常指針(也就是說,指針指向的整型數是可以修改的,但指針是不可修改的)。最後一個意味着a是一個指向常整型數的常指針(也就是說,指針指向的整型數是不可修改的,同時指針也是不可修改的)。
如果應試者能正確回答這些問題,那麼他就給我留下了一個好印象。順帶提一句,也許你可能會問,即使不用關鍵字 ,也還是能很容易寫出功能正確的程序,那麼我爲什麼還要如此看重關鍵字const呢?我也如下的幾下理由:
1) 關鍵字const的作用是爲給讀你代碼的人傳達非常有用的信息,實際上,聲明一個參數爲常量是爲了告訴了用戶這個參數的應用目的。如果你曾花很多時間清理其它人留下的垃圾,你就會很快學會感謝這點多餘的信息。(當然,懂得用const的程序員很少會留下的垃圾讓別人來清理的。)
2) 通過給優化器一些附加的信息,使用關鍵字const也許能產生更緊湊的代碼。
3) 合理地使用關鍵字const可以使編譯器很自然地保護那些不希望被改變的參數,防止其被無意的代碼修改。簡而言之,這樣可以減少bug的出現。
const關鍵字至少有下列n個作用:
(1)欲阻止一個變量被改變,可以使用const關鍵字。在定義該const變量時,通常需要對它進行初始化,因爲以後就沒有機會再去改變它了;
(2)對指針來說,可以指定指針本身爲const,也可以指定指針所指的數據爲const,或二者同時指定爲const;
(3)在一個函數聲明中,const可以修飾形參,表明它是一個輸入參數,在函數內部不能改變其值;
(4)對於類的成員函數,若指定其爲const類型,則表明其是一個常函數,不能修改類的成員變量;
(5)對於類的成員函數,有時候必須指定其返回值爲const類型,以使得其返回值不爲“左值”。例如:
const classA operator*(const classA& a1,const classA& a2);
operator*的返回結果必須是一個const對象。如果不是,這樣的變態代碼也不會編譯出錯:
classA a, b, c;
(a * b) = c; // 對a*b的結果賦值
操作(a * b) = c顯然不符合編程者的初衷,也沒有任何意義。
const修飾類:
(1)const修飾成員變量
const修飾類的成員變量,表示成員常量,不能被修改,同時它只能在初始化列表中賦值。
class A
{
…
const int Value; //成員常量不能被修改
…
A(int x): Value(x) { } ; //只能在初始化列表中賦值
}
(2)const修飾成員函數
const修飾類的成員函數,則該成員函數不能修改類中任何非const成員函數。一般寫在函數的最後來修飾。
class A
{
…
void function()const; //常成員函數, 它不改變對象的成員變量.
//也不能調用類中任何非const成員函數。
}
對於const類對象/指針/引用,只能調用類的const成員函數,因此,const修飾成員函數的最重要作用就是限制對於const對象的使用。
a. const成員函數不被允許修改它所在對象的任何一個數據成員。
b. const成員函數能夠訪問對象的const成員,而其他成員函數不可以。
(3)const修飾類對象/對象指針/對象引用
const修飾類對象表示該對象爲常量對象,其中的任何成員都不能被修改。對於對象指針和對象引用也是一樣。
const修飾的對象,該對象的任何非const成員函數都不能被調用,因爲任何非const成員函數會有修改成員變量的企圖。
例如:
class AAA
{
void func1();
void func2() const;
}
const AAA aObj;
aObj.func1(); ×
aObj.func2(); 正確
const AAA* aObj = new AAA();
aObj-> func1(); ×
aObj-> func2(); 正確