(一) 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
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 *);