關鍵字 extern static const, 聲明和定義的區別

Index:
    (一) extern在C語言中作聲明;
    (二) static變量的作用域, C++中的靜態成員;
    (三) const關鍵字在函數重載中的作用.



(一)extern關鍵字
首先,聲明與定義的區別:
  定義:編譯器會爲變量或函數分配內存  //如:int a=1;
  聲明:只是表明其存在,但沒有分配內存這個過程。//如:int a; 帶或帶extern

extern的兩個作用:
(1)extern聲明/定義變量和函數.
  1.聲明變量或函數, 例如extern int val; extern void fun (void);
    在aaa.cpp 定義函數: void func();
    在bbb.cpp 調用該函數前需要先extern聲明: extern void func();
    或者在aaa.h頭文件裏extern聲明, 所有包含此頭文件的*.cpp都可以是使用func()函數.


(2)當它與"C"一起連用時,例如:
extern "C" {
   void fun(int a, int b);
} // 沒有分號;
則告訴編譯器在編譯fun這個函數名時按着C的規則去翻譯相應的函數名而不是C++的, (原因是C++支持函數的重載,以及...)

使用代碼示例:
#ifdef  __cplusplus
extern "C" {
#endif
  //...函數定義
#ifdef  __cplusplus
}
#endif

http://www.cnblogs.com/skynet/archive/2010/07/10/1774964.html

C++是一個面嚮對象語言(雖不是純粹的面嚮對象語言),它支持函數的重載,重載這個特性給我們帶來了很大的便利。爲了支持函數重載的這個特性,C++編譯器實際上將下面這些重載函數:

void print(int i);
void print(char c);
void print(float f);
void print(char* s);
編譯爲:

_print_int
_print_char
_print_float
_pirnt_string
這樣的函數名,來唯一標識每個函數。注:不同的編譯器實現可能不一樣,但是都是利用這種機制。所以當連接是調用print(3)時,它會去查找_print_int(3)這樣的函數。下

C語言中並沒有重載和類這些特性,故並不像C++那樣print(int i),會被編譯爲_print_int,而是直接編譯爲_print等。因此如果直接在C++中調用C的函數會失敗,因爲連接是調用C中的print(3)時,它會去找_print_int(3)。因此extern "C"的作用就體現出來。



(二)static關鍵字
1.static和extern不能同時修飾一個變量;
2.static修飾的全局變量聲明與定義同時進行,比如static int val,此時變量val所佔的內存已經被分配了.
3.static變量只在該文件內有效,如果.h文件中有定義static double price,那麼每個include此h文件的模塊都有一個單獨的price變量,互不干擾.
4.static函數,如果static函數是類的成員,則此函數只能操作static成員.
5.c++中,類的static成員,不必實例化即可調用,比如Ctype::FuncName(),類的static數據成員,只佔一份內存.
6.如果有如下的函數聲明: static char func(void); 其中的static關鍵字不是修飾返回值char的, 而根據語境, 1修飾函數只在文件內有效, 2如果函數是類成員, 則表明這個函數可以在類沒有實例化前而調用AClass::func();

在C/C++中, static變量都是存儲在常量區, 生存週期都是一旦被創建, 一直存在.
在C語言中, static有了第二種含義:用來表示不能被其它文件訪問的全局變量和函數.
在C+ +中, static還有第三種含義:表示屬於一個類而不是屬於此類的任何特定對象的變量和函數. 對於類的static成員, 該類的所有實例都共用一個static成員.比如在對某一個類的對象進行計數時, 計數生成多少個類的實例, 就可以用到靜態數據成員. 注意, static成員函數必須只能調用static成員.

(三)const關鍵字

在C語言中, 常用#define MAX 1024這樣的宏定義, 但是C++中不推薦這樣做, 而採用const變量的方式定義一個常量.

1. 修飾常量/指針:
       const int *p = &val; //p指向的類型是const int,指向的內容不能改變;
       int const *p = &val; //同上
       int * const p = &vala; //p指向的類型是int,指針本身的值不能改變;
       const int * const p = &a;
2.const對象應該在定義時被賦值, const int* a = new int(0)[1024]; //ok
     
3.多文件中使用const變量:
   extern const char g_str[]; //h文件聲明
   const char g_str[] = "123"; //c文件定義
   
4.函數中指針的const傳遞和返回:  
   const char* F2();   //意義是函數返回的指針指向的對象是一個const對象,它必須賦給一個同樣是指向const對象的指針。 
   const char* const F3();   //比上面多了一個const,這個const的意義只是在他被用作左值時有效,它表明了這個指針除了指向const對象外,它本身也不能被修改,所以就不能當作左值來處理。 
    const char F2(); // 不修飾指針/引用的情況, 無意義, char c = F2() 不報錯.

5.int Func() const; //函數Func()是類成員,表示此函數不能改變類對象,反之則編譯器報錯;


6.const在函數重載中的問題:
   《C++ primer》中提到“僅當形參是引用或指針的時候,形參是否爲const纔對重載有影響。”

const重載情形(1):
    int add(int a, int b);
    int add(const int a, const int b); // 無意義的重載
    在此的兩個函數的形參並不會直接關聯到實參,在調用這兩個函數的時候,形參都只是實參的一個副本,不管add函數內部對 形參做什麼處理,都不會影響到實參,也就是說——第二個函數形參中的const沒有任何的用處,只是多此一舉罷了。所以在此的第二個定義只是對第一個的重 定義罷了。
    實參爲非const對象的時候,其實兩個版本函數都可以被調用,都與之匹配,因爲非const對象不但可以初始化非const引用,也可以初 始化const引用。但由於非const對象初始化const引用的時候涉及到類型轉換,所以此時帶非const引用形參的函數爲最佳匹配。

const重載情形(2):
    int add(int &a, int &b);
    int add(const int &a, const int &b);//可以重載
    比如定義const常量x,y,代碼中調用add(x,y)是第二個版本.

    上述第2種情況:實參爲const對象的時候,就不能將此對象傳遞給帶非const引用的形參的函數了,因爲const對象只能用來初始化const引用。

/*函數定義*/
int add(int *a, int *b);
int add(const int *a, const int *b);

int x = 1;
int y = 2;
const int r = 1;
const int s = 2;

add(&x, &y);  //調用 add(int *, int *);
add(&r, &s);  //調用 add(cosnt int *, cosnt int *);

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