1. 程式人生 > >c/c++中關鍵字static和const的用法

c/c++中關鍵字static和const的用法

一、static

1.在函式體一個被宣告為靜態的變數在這一函式被呼叫的過程中維持其值不變;

2.在模組內,一個被宣告為變數可以被模組內所用,函式訪問,但不能被模組外其他函式訪問,它是一個本地全域性變數;

3.在模組外,一個被宣告為靜態的函式只可被這一模組內的其他函式呼叫,那就是這個函式被限制在宣告它的模組的本地範圍內使用。

4.C++中的類成員宣告static

(1)類的靜態成員函式屬於整個類而非類的物件,所以它沒有this指標,這就導致 了它僅能訪問類的靜態資料和靜態成員函式。      

(2)不能將靜態成員函式定義為虛擬函式。      

(3)由於靜態成員聲明於類中,操作於其外,所以對其取地址操作,就多少有些特殊 ,

變數地址是指向其資料型別的指標 ,函式地址型別是一個“nonmember函式指標”。

(4)由於靜態成員函式沒有this指標,所以就差不多等同於nonmember函式,結果就 產生了一個意想不到的好處:成為一個callback函式,使得我們得以將C++和C-based X W indow系統結合,同時也成功的應用於執行緒函式身上。 (這條沒遇見過)  

(5)static並沒有增加程式的時空開銷,相反她還縮短了子類對父類靜態成員的訪問 時間,節省了子類的記憶體空間。      

(6)靜態資料成員在<定義或說明>時前面加關鍵字static。      

(7)靜態資料成員是靜態儲存的,所以必須對它進行初始化

 (程式設計師手動初始化,否則編譯時一般不會報錯,但是在Link時會報錯誤) 

(8)靜態成員初始化與一般資料成員初始化不同:

初始化在類體外進行,而前面不加static,以免與一般靜態變數或物件相混淆;

初始化時不加該成員的訪問許可權控制符private,public等;        

初始化時使用作用域運算子來標明它所屬類;

所以我們得出靜態資料成員初始化的格式:

<資料型別><類名>::<靜態資料成員名>=<值>

(9)為了防止父類的影響,可以在子類定義一個與父類相同的靜態變數,以遮蔽父類的影響。這裡有一點需要注意:我們說靜態成員為父類和子類共享,但我們有重複定義了靜態成員,這會不會引起錯誤呢?不會,我們的編譯器採用了一種絕妙的手法:name-mangling 用以生成唯一的標誌

二、const

1. const 在C和C++中的區別

C++中的const正常情況下是看成編譯期的常量,編譯器並不為const分配空間,只是在編譯的時候將期值儲存在名字表中,並在適當的時候摺合在程式碼中. 所以在C++中const修飾的量可以用在陣列的定義中。

而在C中,const是一個不能被改變的普通變數,既然是變數,就要佔用儲存空間,所以編譯器不知道編譯時的值.而且,陣列定義時的下標必須為常量.

在C語言中: const int size; 這個語句是正確的,因為它被C編譯器看作一個宣告,指明在別的地方分配儲存空間.

但在C++中這樣寫是不正確的.

C++中const預設是內部連線,如果想在C++中達到以上的效果,必須要用extern關鍵字. C++中,const預設使用內部連線.而C中使用外部連線.

內連線:編譯器只對正被編譯的檔案建立儲存空間,別的檔案可以使用相同的表示符或全域性變數.C/C++中內連線使用static關鍵字指定.

外連線:所有被編譯過的檔案建立一片單獨儲存空間.一旦空間被建立,聯結器必須解決對這片儲存空間的引用.全域性變數和函式使用外部連線.通過extern關鍵字宣告,可以從其他檔案訪問相應的變數和函式. C++中,是否為const分配空間要看具體情況. 如果加上關鍵字extern或者取const變數地址,則編譯器就要為const分配儲存空間.

C++中定義常量的時候不再採用define,因為define只做簡單的巨集替換,並不提供型別檢查.

2.const指標和指向const的指標

在C語言中const指標表示該指標是一個常量,一旦進行初始化完成之後就無法改變它指向的位置。指向const的指標說明使用這個指標無法改變其指向的地址處的值,特別強調的一點是使用這個指標不能夠改變。言外之意就是說,可以通過其他的方式改變。

比如:char ch='c';

const char *ptr=&ch;

*ptr='a';//這樣做是不允許的

ch='a';//這樣做完全可以,並且*ptr的值也是'a'

const用法小結:

const最常用的就是定義常量,除此之外,它還可以修飾函式的引數、返回值和函式的定義體。
1. const修飾函式的引數
如果引數作輸出用,不論它是什麼資料型別,也不論它採用“指標傳遞”還是“引用傳遞”,都不能加const 修飾,否則該引數將失去輸出功能。
const 只能修飾輸入引數:
如果輸入引數採用“指標傳遞”,那麼加const 修飾可以防止意外地改動該指標,起到保護作用。
將“const &”修飾輸入引數的用法總結如下:
(1)對於非內部資料型別的輸入引數,應該將“值傳遞”的方式改為“const 引用傳遞”,目的是提高效率。例如將void Func(A a) 改為void Func(const A &a)。
(2)對於內部資料型別的輸入引數,不要將“值傳遞”的方式改為“const 引用傳遞”。否則既達不到提高效率的目的,又降低了函式的可理解性。例如void Func(int x) 不應該改為void Func(const int &x)。
2. const 修飾函式的返回值
如果給以“指標傳遞”方式的函式返回值加const 修飾,那麼函式返回值(即指標)的內容不能被修改,該返回值只能被賦給加const 修飾的同類型指標。例如函式
const char * GetString(void);
如下語句將出現編譯錯誤:
char *str = GetString();
正確的用法是
const char *str = GetString();

如果返回值不是內部資料型別,將函式A GetA(void) 改寫為const A & GetA(void)的確能提高效率。但此時千萬千萬要小心,一定要搞清楚函式究竟是想返回一個物件的“拷貝”還是僅返回“別名”就可以了,否則程式會出錯。
函式返回值採用“引用傳遞”的場合並不多,這種方式一般只出現在類的賦值函式中,目的是為了實現鏈式表達。
例如:

class A
{
A & operate = (const A &other); // 賦值函式
};
A a, b, c; // a, b, c 為A 的物件
a = b = c; // 正常的鏈式賦值 (a = b) = c; // 不正常的鏈式賦值,但合法 如果將賦值函式的返回值加const 修飾,那麼該返回值的內容不允許被改動。上例中,語句 a = b = c 仍然正確,但是語句 (a = b) = c 則是非法的。
3. const修飾成員函式
關於Const函式的幾點規則:
1). const物件只能訪問const成員函式,而非const物件可以訪問任意的成員函式,包括const成員函式.
2). const物件的成員是不可修改的,然而const物件通過指標維護的物件卻是可以修改的.
3). const成員函式不可以修改物件的資料,不管物件是否具有const性質.它在編譯時,以是否修改成員資料為依據,進行檢查.
4). 然而加上mutable修飾符的資料成員,對於任何情況下通過任何手段都可修改,自然此時的const成員函式是可以修改它的