主表達式
主表達式是更復雜的表達式的構造塊。它們是文本、名稱以及范圍解析運算符 (::) 限定的名稱。主表達式可以具有以下任一形式:
literalthis:: namename ( expression )
literal 是常量主表達式。其類型取決于其規范的形式。
this 關鍵字是指向類對象的指針。它在非靜態成員函數中可用,并指向為其調用函數的類的實例。 this 關鍵字只能在類成員函數體的外部使用。
this 指針的類型是未特別修改 this 指針的函數中的 type *const(其中 type 是類名)。以下示例演示成員函數聲明以及 this 的類型:
// expre_Primary_Expressions.cpp// compile with: /LDclass Example{public: void Func(); // * const this void Func() const; // const * const this void Func() volatile; // volatile * const this};
范圍解析運算符 (::) 后跟名稱構成了主表達式。此類名稱必須是全局范圍內的名稱,而不是成員名稱。此表達式的類型由名稱的聲明決定。如果聲明的名稱是左值,則該類型是左值(即,它可以出現在賦值運算符表達式的左側)。范圍解析運算符允許引用全局名稱,即使該名稱隱藏在當前范圍中也如此。
用括號括起的表達式是與不帶括號的表達式具有相同的類型和值的主表達式。如果不帶括號的表達式是左值,則用括號括起的表達式也是左值。
在上面給出的主表達式語法的上下文中,name 表示為 name 描述的語法中的任何內容,不過,當在名稱前使用范圍解析運算符時,不允許使用只能在類中出現的名稱的類型。這包括用戶定義的轉換函數名稱和析構函數名稱。
主表達式的示例包括:
100 // literal'c' // literalthis // in a member function, a pointer to the class instance::func // a global function::operator + // a global operator function::A::B // a global qualified name( i + 1 ) // a parenthesized expression
下面的示例是所有考慮的 name 以及各種形式的主表達式:
MyClass // a identifierMyClass::f // a qualified nameoperator = // an operator function nameoperator char* // a conversion operator function name~MyClass // a destructor nameA::B // a qualified nameA<int> // a template id
后綴表達式
后綴表達式包含主表達式或者其中的后綴運算符跟在主表達式之后的表達式。 下表列出了后綴運算符。
后綴運算符
運算符名稱
運算符表示法
下標運算符
[ ]
函數調用運算符
( )
顯式類型轉換運算符
type-name ( )
成員訪問運算符
. 或 –>
后綴遞增運算符
++
后綴遞減運算符
––
以下語法描述了可能的后綴表達式:
primary-expression postfix-expression [ expression ]postfix-expression ( expression-list)simple-type-name ( expression-list)postfix-expression . namepostfix-expression –> namepostfix-expression ++postfix-expression ––cast-keyword < typename > (expression )typeid ( typename )
上面的 postfix-expression 可能是主表達式或另一個后綴表達式。 請參閱主表達式。 后綴表達式從左到右進行分組,這允許表達式按如下方式鏈接起來:
func(1)->GetValue()++
在上面的表達式中,func 是主表達式,func(1) 是函數后綴表達式,func(1)->GetData 是指定類成員的后綴表達式,func(1)->GetData() 是另一個函數后綴表達式,整個表達式是增加 GetData 的返回值的后綴表達式。 該表達式的整體含義是作為參數傳遞 1 的 "call func,并作為返回值獲取一個指向類的指針。 然后調用此類上的 GetValue(),接著遞增返回的值。
上面列出的表達式是賦值表達式,這意味著這些表達式的結果必須為右值。
后綴表達式形式
simple-type-name ( expression-list )
指示構造函數的調用。 如果 simple-type-name 是基本類型,則表達式列表必須是單個表達式,并且該表達式指示表達式的值將轉換為基礎類型。 此類強制轉換表達式模仿構造函數。 由于此形式允許使用相同的語法來構造基本類型和類,因此它在定義模板類時特別有用。
cast-keyword 是 dynamic_cast、static_cast 或 reinterpret_cast 之一。 可在 dynamic_cast、static_cast 和 reinterpet_cast 中找到更多信息。
typeid 運算符被視為后綴表達式。 請參閱 typeid 運算符。
形參和實參
調用程序會將信息傳遞到“實參”中的已調用函數。 已調用函數使用對應的“形參”訪問信息。
當調用函數時,將執行以下任務:
計算所有實參(調用方提供的參數)。 沒有計算這些參數的隱含順序,但所有參數都會計算,并且所有副作用都會在進入該函數前完成。
使用每個形參在表達式列表中對應的實參來初始化該形參。 (形參是在函數頭中聲明并在函數體中使用的參數。) 轉換就像是通過初始化完成的一樣 - 標準的和用戶定義的轉換在將實參轉換為正確的類型時執行。 以下代碼從概念上演示了所執行的初始化:
void Func( int i ); // Function prototype...Func( 7 ); // Execute function call
調用前的概念性初始化為:
int Temp_i = 7;Func( Temp_i );
請注意,初始化就像使用等號語法(而不是括號語法)一樣執行。 在將值傳遞到函數之前制作了 i 的副本。
因此,如果函數原型(聲明)對 long 類型的參數進行調用,并且調用程序提供了 int 類型的實參,則會使用到 long 類型的標準類型轉換提升該實參。
如果提供了一個實參,但它沒有到形參的類型的標準的或用戶定義的轉換,則是一個錯誤。
對于類類型的實參,將通過調用類的構造函數初始化形參。
執行函數調用。
以下程序片段演示了函數調用:
// expre_Formal_and_Actual_Arguments.cppvoid func( long param1, double param2 );int main(){ long i = 1; double j = 2; // Call func with actual arguments i and j. func( i, j );}// Define func with formal parameters param1 and param2.void func( long param1, double param2 ){}
當從 main 調用 func 時,將使用 param1(i 將轉換為類型 ilong 以對應使用標準轉換的正確類型)的值初始化形參 ,并使用 param2(j 將轉換為使用標準轉換的類型 jdouble)的值初始化形參 。
參數類型的處理
不能在函數主題內更改聲明為 const 類型的形參。 函數可以更改類型不是 const 的任何參數。 但是,更改對于函數而言是本地進行的,且不會影響實參的值,除非實參是對非 const 類型的對象的引用。
以下函數闡釋了其中的一些概念:
// expre_Treatment_of_Argument_Types.cppint func1( const int i, int j, char *c ) { i = 7; // C3892 i is const. j = i; // value of j is lost at return *c = 'a' + j; // changes value of c in calling function return i;}double& func2( double& d, const char *c ) { d = 14.387; // changes value of d in calling function. *c = 'a'; // C3892 c is a pointer to a const object. return d;}
省略號和默認參數
通過使用下列兩種方法之一,可以聲明函數以接受比函數定義中指定的參數更少的參數:省略號 (...) 或默認參數。
省略號表示可能需要參數,但聲明中未指定數目和類型。 這通常是較差的 C++ 編程做法,因為它使您無法獲得 C++ 的一個優點,即類型安全。 不同的轉換將應用于使用省略號聲明的函數,而不是應用于那些已知其形參和實參類型的函數:
如果實參的類型為浮點,則在函數調用前將其提升為雙精度類型。
使用整型提升將所有有符號或無符號的 char、short、枚舉類型或位域轉換為有符號或無符號的 int。
類類型的所有參數都作為數據結構通過值進行傳遞;副本是由二進制復制創建的,而不是通過調用類的復制構造函數(如果存在)創建的。
如果使用省略號,則必須在參數列表中最后聲明它。
如果函數調用中沒有提供值,則可通過默認參數指定參數應采用的值。 以下代碼片段演示默認參數的工作方式。
// expre_Ellipses_and_Default_Arguments.cpp// compile with: /EHsc#include <iostream>// Declare the function print that prints a string,// then a terminator.void print( const char *string, const char *terminator = "/n" );int main(){ print( "hello," ); print( "world!" ); print( "good morning", ", " ); print( "sunshine." );}using namespace std;// Define print.void print( const char *string, const char *terminator ){ if( string != NULL ) cout << string; if( terminator != NULL ) cout << terminator;}
上面的程序聲明一個采用兩個參數的函數 print。 而第二個參數 terminator 具有默認值 "/n"。 在 main 中,對 print 的前兩個調用允許默認的第二個參數提供新行以終止打印的字符串。 第三個調用為第二個參數指定顯式值。 該程序的輸出為
hello,world!good morning, sunshine.