C++的那點事,const的所有用法

C++中的const的用法可謂博大精深,活用const對於代碼的健壯性,可讀性都有很大的幫助。如果面試官問你const的用法時,可千萬不能只說:定義只讀類型。

 

一、對於基本聲明

1.const int r=100;

//標準const變量聲明加初始化,因爲默認內部連接所以必須被初始化,其作用域爲此文件,編譯器經過類型檢查後直接用100在編譯時替換。

 

2.extend const int r=100;

//將const改爲外部連接,作用於擴大至全局,編譯時會分配內存,並且可以不進行初始化,僅僅作爲聲明,編譯器認爲在程序其他地方進行了定義。

 

3.const int r[ ]={1,2,3,4};

struct S {int a,b;};

const S s[ ]={(1,2),(3.4)};

//以上兩種都是常量集合,編譯器會爲其分配內存,所以不能在編譯期間使用其中的值,

//例如:int temp[r[2]]; 這樣的編譯器會報告不能找到常量表達式

 

二、對於指針

1.const int *r=&x;

//聲明r爲一個指向常量的x的指針,r指向的對象不能被修改,但他可以指向任何地址的常量。

//就是說這個指針只能指向的內容一定是常量了!!!!地址內存可變

 

2.int const *r=&x;

//與用法1完全等價,沒有任何區別。

 

3.int * const r=&x;

//聲明r爲一個常量指針,他指向x,這個指針的指向不能被修改,但他指向的地址的內容可以修改。

//這個指針指向的地址不可變是個固定的常量,地址所表示的內容可變

 

4.const int * const r=&x;

//綜合1、3用法,r是一個指向常量的常量型指針

 

三、對於類型檢查

可以把一個非const對象賦給一個指向const的指針,因爲有時候我們不想從這個指針來修改其對象的值;

但是不可以把一個const對象賦值給一個非const指針,因爲這樣可能會通過這個指針改變指向對象的值,

但也存在使這種操作通過的合法化寫法,使用類型強制轉換可以通過指針改變const對象

const int r=100;

int * ptr = const_cast(&r); //C++標準,C語言使用:int * ptr =(int*)&r;

 

四、對於字符數組

如char * name = “china”;

這樣的語句,在編譯時是能夠通過的,但是”china”是常量字符數組,任何想修改他的操作也能通過編譯但會引起運行時錯誤

如果我們想修改字符數組的話就要使用char name[ ] = “china”; 這種形式。

 

五、對於函數

1.void Fuction1 ( const int r );

//此處爲參數傳遞const值,意義是變量初值不能被函數改變

 

2.const int Fuction1 (int);

//此處返回const值,意思指返回的原函數裏的變量的初值不能被修改,但是函數按值返回的這個變量被製成副本,能不能被修改就沒有了意義,它可以被賦給任何的const或非const類型變量,完全不需要加上這個const關鍵字。

這隻對於內部類型而言(因爲內部類型返回的肯定是一個值,而不會返回一個變量,不會作爲左值使用),對於用戶自定義類型,返回值是常量是非常重要的,見下麪條款3。

 

3.Class CX; //內部有構造函數,聲明如CX(int r =0)

CX Fuction1 () { return CX(); }

const CX Fuction2 () { return CX(); }

如有上面的自定義類CX,和函數Fuction1()和Fuction2(),我們進行如下操作時:

Fuction1() = CX(1); //沒有問題,可以作爲左值調用

Fuction2() = CX(1); //編譯錯誤,const返回值禁止作爲左值調用。因爲左值把返回值作爲變量會修改其返回值,const聲明禁止這種修改。


 

4.函數中指針的const傳遞和返回:

int F1 (const char * pstr);

//作爲傳遞的時候使用const修飾可以保證不會通過這個指針來修改傳遞參數的初值,這裏在函數內部任何修改*pstr的企圖都會引起編譯錯誤


const char * F2 ();

//意義是函數返回的指針指向的對象是一個const對象,它必須賦給一個同樣是指向const對象的指針

const char * const F3();

//比上面多了一個const,這個const的意義只是在他被用作左值時有效,它表明了這個指針除了指向const對象外,它本身也不能被修改,所以就不能當作左值來處理

 

5.函數中引用的const傳遞:

void F1 ( const X& px);

//這樣的一個const引用傳遞和最普通的函數按值傳遞的效果是一模一樣的,他禁止對引用的對象的一切修改,唯一不同的是按值傳遞會先建立一個類對象的副本,然後傳遞過去,而它直接傳遞地址,所以這種傳遞比按值傳遞更有效

**另外只有引用的const傳遞可以傳遞一個臨時對象,因爲臨時對象都是const屬性,且是不可見的,他短時間存在一個局部域中,所以不能使用指針,只有引用的const傳遞能夠捕捉到這個傢伙。 

 

六、對於類

1.首先,對於const的成員變量,只能在構造函數裏使用初始化成員列表來初始化,試圖在構造函數體內進行初始化const成員變量會引起編譯錯誤。初始化成員列表形如:

X:: X ( int ir ): r(ir) {} //假設r是類X的const成員變量

 

2.const成員函數。

提到這個概念首先要談到const對象,正象內置類型能夠定義const對象一樣(const int r=10;),用戶自定義類型也可以定義const對象(const X px(10);),編譯器要保證這個對象在其生命週期內不能夠被改變。如果你定義了這樣的一個const對象,那麼對於這個對象的一切非const成員函數的調用,編譯器爲了保證對象的const特性,都會禁止並在編譯期間報錯。所以如果你想讓你的成員函數能夠在const對象上進行操作的話,就要把這個函數聲明爲const成員函數

假如f( )是類中的成員函數的話,它的聲明形如:

int f( ) const;

//const放在函數的最後,編譯器會對這個函數進行檢查,在這個函數中的任何試圖改變成員變量和調用非const成員函數的操作都被視爲非法

注意:類的構造和析構函數都不能是const函數

 

3.建立了一個const成員函數,但仍然想用這個函數改變對象內部的數據。這樣的一個要求也會經常遇到,尤其是在一個苛刻的面試考官那裏。首先我們要弄清楚考官的要求,因爲有兩種方法可以實現,如果這位考官要求不改變原來類的任何東西,只讓你從當前這個const成員函數入手,那麼你只有使用前面提到的類型強制轉換方法。實例如下:

//假如有一個叫做X的類,它有一個int成員變量r,我們需要通過一個const成員函數f( )來對這個r進行++r操作,代碼如下

void X::f( ) const

{ (const_cast(this)) -> ++r; } //通過this指針進行類型強制轉換實現

另外一種方法就是使用關鍵字:mutable。如果你的成員變量在定義時是這個樣子的:

mutable int r ;

那麼它就告訴編譯器這個成員變量可以通過const成員函數改變。編譯器就不會再理會對他的檢查了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章