淺析extern、static、const
extern
C和C++中用extern關鍵字修飾變數或函式,說明該變數或函式是全域性性的。extern宣告的外部變數和函式告訴編譯器,該變數和函式的宣告和定義不在同一檔案中,而要在其他檔案中查詢定義。
變數在被extern宣告時並不對其分配有效空間,而是在定義時分配空間。
extern與“C”連用
這是在C++中的使用方法,比如:extern "C"+函式宣告,則告訴編譯器按照C語言的函式命名規則去編譯後面的函式,而不是C++的函式命名規則。其實C語言與C++的函式命名規則是不一樣的。
static
static關鍵字是C,C++共有的。 被static修飾的變數(函式)具有了靜態屬性,稱他們為靜態變數(函式)。具體用法有三種:
1.用static宣告靜態區域性變數。
2.用static宣告靜態外部變數或函式。
3.用static宣告靜態資料成員或成員函式。
其中第三點是C++中所特有的,因為C語言中沒有類的概念也就沒有資料成員和成員函式。
一、靜態區域性變數
在函式內部用static宣告的變數為靜態區域性變數,普通型別的變數是被分配到棧中儲存,而靜態型別的變數是被分配到靜態區儲存。被分配到靜態區的變數在函式呼叫結束後,它的值和儲存單元不被系統自動釋放而是保留原值,在下一次函式呼叫時保留上次函式呼叫後的值。等改程式執行完後再由系統清除。
總結int Test() { static int c = 1; c++; return c; } int main() { printf("%d\n", Test()); printf("%d\n", Test()); //每次呼叫完成後值保留 system("pause"); return 0; }
1.靜態區域性變數在靜態儲存區內分配儲存單元。
2.對靜態區域性變數是在編譯時賦初值的,即只賦初值一次,在程式執行時它已有初值。
3.在定義靜態區域性變數時如果沒有賦初值,則系統給該變數預設賦值為0。
4.宣告在本函式內部的靜態區域性變數不可以被其他函式呼叫。
二、靜態外部變數
在函式外部用static修飾的變數或者函式它的作用域被限制在本檔案範圍內,不能被其他檔案呼叫。此時的靜態變數或函式並不是採用靜態儲存方式(分配在靜態儲存區),而是他們的作用域被限制在本檔案。無論外部變數是否有static修飾,它都是被儲存在靜態區中。
三、靜態資料成員、靜態成員函式//file1.cpp static int a=1; static void Test() { } int main() { } //file2.cpp extern int a; //錯誤,無法使用file1.cpp中定義的static變數 extern void Test(); //錯誤,無法使用file1.cpp中定義的static函式
靜態資料成員和靜態成員函式是C++所特有的性質,靜態資料成員是各物件所共有的,物件中資料成員的值是一樣的,是屬於類的,所有物件都可以應用它。靜態資料成員在記憶體中只佔用一份空間,如果改變它的值,則在各物件中這個資料成員的值都會同時改變。這樣就節省了空間,提高執行效率。
總結
1、靜態成員為所有類物件所共享,不屬於某個具體的例項。
2、類靜態成員即可用類名::靜態成員或者物件.靜態成員來訪問
3、類靜態成員變數必須在類外定義,定義時不新增static關鍵字
4、類的靜態成員函式沒有預設的this指標,因此在它裡面不能使用任何非靜態成員
5、靜態成員和類的普通成員一樣,也有public、protected、private3種訪問級別,也可以具有返回值,const修飾符等引數。
注意
1.靜態成員函式不能訪問非靜態成員(資料、函式),只能訪問靜態成員(資料、函式)。
2.非靜態成員函式可以訪問靜態成員(資料、函式)。
const
被const修飾的變數是不能夠修改的。const int a=10,在C語言中a是一個不可修改的常量,而在C++中a是一個常量,在C++中利用const常量取代了C語言中的巨集定義。需要特別注意的是,被const修飾的變數在宣告的時候必須初始化。
一、const常量和define
在C語言中要想使用一個常量通常會在檔案頭利用define來定義,但這種方法在C++中認為是不好,不安全的。C++中利用const常量來取代它。二者的優缺點對比如下:
C語言中的巨集:
1.不進行型別檢測。
2.不能除錯.
3.容易造成程式碼膨脹,降低效率。
而C++中的const常量是可除錯,並進行型別檢測的。
二、const指標
const修指標有兩種用法,一種是修飾指標指向的物件,一種是修飾指標的本身。在這裡通過一種簡單的方法來進行區分,將指標型別隱藏,然後看const關鍵字右邊的第一個字元。如果是指標變數,則說明const修飾的是指標變數本身,如果是*,則說明的修飾的是指標變數指向的物件。
const int *p1; //const修飾指標p1指向的物件,p1可變,p1指向的物件不可變
int const *p2; //同上
int* const p3; //const修飾指標p3,p3不可變,p3指向的物件可變
const int* const p4; //同上
例子中第一條語句和第二條語句屬於同一型別,第三條和第四條語句屬於同一型別。
三、const函式引數
將函式引數宣告為const,說明使用這種引數是為了提高程式執行效率和提高安全性,這樣函式在呼叫該物件時,在函式內部就不能對物件的值進行修改。同理,將指標引數宣告為const,函式將不修改由這個引數所指的物件。
void Test1(const int a); //函式不能修改變數a
void Test2(const char* b); //函式不能修改指標b指向的變數
四、const修飾函式返回值
可以阻止使用者修改返回值。格式如下:
const int Test();
五、const修飾類成員
const修飾類成員是C++中所特有的性質,這裡包括類資料成員、類物件和類成員函式。
1.被const修飾的資料成員,必須在建構函式的初始化列表中初始化。
class A
{
public:
A(int b = 0)
:_a(0) //必須在初始化列表中初始化
{
_b = b;
}
const int _a;
private:
int _b;
};
2.被const修飾的類物件為常物件,同樣常物件在定義的時候必須要有初值。在常物件的生命週期中,它的資料成員的值都是不能被修改的。
A const a1(1); //定義常物件a1
定義常物件的一般格式:
類名 const 物件名[(實參表)];
或者
const 類名 物件名[(實參表)];
注意
常物件只能呼叫常成員函式,不能呼叫普通成員函式。而非const物件既可以呼叫普通成員函式,也可以呼叫常成員函式。
3.普通的成員函式可以呼叫本類中的非const成員,並可以在函式中修改它們。如果將成員函式宣告為常成員函式,則只能引用本類中的資料成員,而不能修改它們。
void Display()const; //const在函式名和括號的最後邊
注意
1.常成員函式的宣告和定義時都要在括號的最後邊加const關鍵字。
2.常成員函式只能呼叫const成員函式,不能呼叫非const成員函式。
3.非const成員函式內可以呼叫其它的const成員函式和非const成員函式。
總結
資料成員 | 非const的普通成員函式 | const成員函式 |
非const的普通資料成員 | 可以引用,可以改變值 | 可以引用,不可以改變值 |
const資料成員 | 可以引用,不可以改變值 | 可以引用,不可以改變值 |
const物件 | 不可以引用 | 可以引用,不可以改變值 |