C/C++語言的聲明文法比較晦澀難懂,特翻譯Accelerated C++中附錄對此的解釋,希望對大家有所協助。
A.1 聲明
一些聲明可能難以理解,特別是如果聲明幾個不同類型的名字或者那些指向函數指標的函數。例如在§10.1.1/171中,我們看到
int* p, q;
定義p為一個“整型指標”類型的對象,q為一個整型對象。在§10.1.2/173中,我們看到
double (*get_analysis_ptr())(const vector<Student_info>&);
聲明get_analysis_ptr為一個函數,不帶任何參數,它返回一個指標,它指向一個函數,它帶有一個const vector<Student_info>&參數,返回double。你可以通過重寫以清楚的表達這些聲明的含義,例如
int* p;
int q;
和
// 定義analysis_fp為一個函數,它帶一個const vector<Student_info>&參// 數,返回一個double類型。
typedef double (*analysis_fp)(const vector<Student_info>&);
analysis_fp get_analysis_ptr();
不幸的是,這種策略不會協助你閱讀其它程式員代碼中令人迷惑的聲明。
一般,一個聲明大致如下
聲明語句:聲明說明符[聲明子[初始化器]] [,聲明子[初始化器]]...;
它為每一個聲明子聲明一個名字。這些名字始於聲明開始的地方終於聲明範圍結束的地方。一些聲明同時也是定義。名字可以聲明多次,但是僅能定義一次。如果一個聲明分配了儲存空間或者定義了類或函數體,那麼它也是一個定義。
C++繼承了C的聲明文法。理解聲明的關鍵是認識到每個聲明包含兩個部分:一系列聲明說明符,它們一起說明一個類型和其它正在聲明的特性,緊跟著是零個或多個聲明子(每個聲明子都可選的有一個關聯的初始化器)。根據說明符和聲明子的形式,每個聲明子都為名字賦予一個類型。
理解聲明的第一步是定位說明符和聲明子的邊界。這很容易:所有的說明符都是關鍵字或者類型名,因此說明符終止於第一個不是以上類型之一的符號。例如,在
const char * const * const * cp;
很容易找到邊界:double是一個類型,左括弧後面既不是關鍵字也不是類型名。因此,聲明—說明符只是double,聲明子為聲明的其它部分,不包含分號。
double (*get_analysis_ptr())(const vector<Student_info>&);
另一個例子,考慮§10.1.2/173中的聲明:
第一個既不是關鍵字也不是類型名的符號是*,因此說明符是const char,唯一的聲明子* const * const * cp。
A.1.1 說明符(Specifiers)
我們可以將聲明—說明符分成三個部分:類型說明符,儲存類說明符,和其它說明符:
聲明說明符:{類型說明符|儲存類說明符|其它聲明說明符}
然而,這種劃分僅僅有助於理解,因為聲明本身不存在對應的劃分:聲明—說明符可以以任何次序出現。
類型說明符決定了聲明的類型。我們在§A.2/299中討論內建類型。
type-specifier: char | wchar_t | bool | short | int | long | signed
unsigned | float | double | void | type-name | const | volatile
type-name: class-name | enum-name | typedef-name
const說明符指出這種類型的對象不可以修改,volatile通知編譯器變數可能以非語言定義的形式改變,應該避免最佳化。
注意const既可以出現在說明符部分,這樣修改類型,也可以出現在聲明子部分,說明一個const指標。這沒有任何歧義,因為聲明子部分的const總是跟著一個*。
儲存類說明符決定變數的位置和生命週期:
storage-class-specifiers: register | static | extern | mutable
register說明符建議編譯器通過將此對象放到寄存器中以最佳化效能。
一般,局部變數在退出聲明它們的塊(block)時即被銷毀;靜態變數的值在範圍的入口和出口間會被儲存起來。
extern說明符表明當前的聲明不是一個定義,隱含著在其它地方存在相應的定義。
mutable儲存類僅用於類的資料成員,並且允許修改這些資料成員即使它們是常量對象的成員。
其它聲明說明符定義了與類型無關的屬性:
other-decl-specifier: friend | inline | virtual | typedef
friend說明符(§12.3.2/216 and §13.4.2/246)改防寫保護。
內聯說明符用於函數定義,提示編譯器如果可能內聯下面的代碼。當展開調用時,函數定義必須出現在那個範圍,因此將內嵌函式體放到聲明函數的標頭檔中通常是一個好主意。
virtual說明符(§13.2.1/234)僅用於成員函數,表示這個函數是動態綁定的。
typedef說明符(§3.2.2/43)定義類型的同義字。
A.1.2 聲明子(Declarators)-未完待續