C++程式設計過程中,const的使用可以頻度是非常高的.它在保證程式安全方面起到了不可估量的作用.
用一句話來表達最確切不過了:」小兵立大功」.
有了const,那麼mutable當然缺不了.
然作為const的同胞兄弟,volatile卻在很多人的視野中消失.其實volatile擔負的責任有何嘗小呢?
自然,它們的用法多樣而靈巧,以至新手迷惑久久,下面就來系統的探討總結一下吧:
一.一般應用
1.const修飾各種變量的用法.
a.取代define
#define D_INT 100
#define D_LONG 100.29
………
const int D_INT = 100;
const D_INT = 100; //如果定義的int類型,可省略int.
const long D_LONG = 100.29;
………
const int& a = 100;
const替代define雖然增加分配空間,可它卻保證了類型安全.
在C標準中,const定義的數據相當於全局的,而C++中視宣告的位置而定.
b.修飾指標相關的變量
以三組簡單的定義示意:
Group1:
const int* b = &a;------------ [1]
int const *b = &a;------------ [2]
const int* const b = &a;---- [4]
Group2:
char const *p = "const";--------------[2]
char* const p = "const";--------------[3]
const char * const p = "const";----[4]
Group3:
const int &b = a;---------------[1]
int const &b = a;---------------[2]
int & const b = a;--------------[3] //--->修飾引用時,const被忽略
const int & const b = a;-----[4]
總結:
1.如果const位於星號左側,則const用來修飾指標所指向的變量,
即指標指向的為不可變的.
2.如果const位於星號右側,const就是修飾指標本身,即指標本身是
不可變的.
因此,[1]和[2]的情況相同,指標所指向內容不可變(const放在變量
聲明符的位置無關),這種情況下不允許對內容進行更改,如不能*a = 3 ;
3.[3]中指標本身是不可變的,而指標所指向的內容是可變的,這種情況
下不能對指標本身進行更改操作,如a++是錯誤的
4.[4]中指標本身和指向的內容均為常量.(引用特殊:引用在使用增加
遇義時,增加它代表的變量.所以qualifiers on reference are ignoredv.
延伸點:
注意範例:
1.const int& reference = 1000;
2.char* p = "const"
char*& q ;
2.const在函數環境下的各種應用
常用法示例如下:
const A& _Fun(const A& _in); //修飾引用型傳入參數
// A _Fun(const A& _in);
//A& _Fun(const A& _in);
//上面的兩種,在函數內部有特殊的步驟,這裡不詳提了…..
const A* _Fun( const A* _in); //修飾指針型傳入參數
void _Fun( ) const; //修飾class成員函數
const A& _Fun(A& _in ); //修飾返回值
const A & operator(const A& _in); //同時修飾傳入參數和返回值
a.修飾參數
如void _Fun(const A* _in)或 void _Fun(const A& _in);
它們被修飾後,在函數執行期間行為特性同於上面的講解,
注意:這不會改變原來數據的是否是const的屬性.
b.修飾函數返回值
const A& _Fun( )
const A* _Fun( );
注意:由於生命期不同步的問題,不可將局部的變量的指標或引用返回(static除外).
另外,傳出來的視情況,代表不同的意思…
對於A&返回類型,你若將之賦與其它變量,那麼它實際執行的是將返回的變量
(或引用)代表的數據賦出..而你若將其它值賦予之,那麼被賦予的是變量或引
用代表的數據. 而const A& 一般是防止之做為左值被賦值.
這個地方還有很多的細節問題(譬如在連續賦值、返回的臨時物件的處理、
重載的const和非cosnt運算符等等),讀者自己在實踐中需要多多總結.
二、難點
3. 修飾類成員函數的const.
形如:void _Fun() const { };
你需要知道的幾點規則:
a.const對象只能訪問const成員函數,而非const物件可以存取任意
的成員函數,包括const成員函數.
b.const物件的成員是不可修改的,然而const物件通過指標維護的對象卻
是可以修改的.
c.const成員函數不可以修改物件的資料,不管對像是否具有const性質.它在
編譯時,以是否修改成員資料為依據,進行檢查.
e.然而加上mutable修飾符的資料成員,對於任何情況下通過任何手段
都可修改,自然此時的const成員函數是可以修改它的…
4.談談volatile和」完全const物件」
一個有volatile修飾的類只允許訪問其接口的一個子集,這個子集由類的
實現者來控制.用戶只有用const_cast才可以訪問這個類型的全部接口.而且,
象const一樣,類的volatile屬性會傳遞給它的成員.想像const修飾的對
象,它的成員變量是不可修改的,而它通過指針維護的對象或原生變量是可
修改.那麼我們想:如果對象維護一個char* ,則它相當於char*
const chrptr ;而不是const char* cosnt chrptr;對於類中的指針你需要
這樣修飾以防止它或它維護的資源:cosnt x* xptr;而不是x*const xptr;
因為cosnt 修飾的對像它默認 的行為是延續變量:x* cosnt xptr;
更重要的,volatile修飾的數據,編譯器不可對其進行執行期寄存於寄存器的優化.
這種特性,是為了多線程同步的需要.有興趣者看參看Andrei的GP系列文章.
5.談談const_cast轉換運算符
這個關鍵字最基礎的用法是:去掉數據的const性質.
值得注意的是:它只對指針、引用和其它的具有指向性質的類型.
參考:
1.《Effective C++ 》關於const兩種語義的論述
2.Andrei Alexandrescu 《volatile——編寫多線程程序的好幫手》