1. 程式人生 > >淺析extern、static、const

淺析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物件 不可以引用 可以引用,不可以改變值