包含變量參數列表的函數
如果函數聲明中最后一個成員是省略號 (...),則函數聲明可采用數量可變的參數。在這些情況下,C++ 只為顯式聲明的參數提供類型檢查。即使參數的數量和類型是可變的,在需要使函數泛化時也可使用變量參數列表。函數的系列是一個使用變量參數列表的函數的示例。printfargument-declaration-list
包含變量參數的函數
若要訪問聲明后的參數,請使用包含在標準包含文件 STDARG.H 中的宏(如下所述)。
采用數量可變的參數的函數聲明至少需要一個占位符參數(即使不使用它)。如果未提供此占位符參數,則無法訪問其余參數。
當 char 類型的參數作為變量參數進行傳遞時,它們將被轉換為 int 類型。同樣,當 float 類型的參數作為變量參數進行傳遞時,它們將被轉換為 double 類型。其他類型的參數受常見整型和浮點型提升的限制。
使用參數列表中的省略號 (...) 來聲明需要變量列表的函數。使用在 STDARG.H 包含文件中描述的類型與宏來訪問變量列表所傳遞的參數。有關這些宏的詳細信息,請參閱 va_arg、va_copy、va_end、va_start。(處于 C 運行時庫文檔中)。
以下示例演示如何將宏與類型一起使用(在 STDARG.H 中聲明):va_listva_endva_argva_start
// variable_argument_lists.cpp#include <stdio.h>#include <stdarg.h>// Declaration, but not definition, of ShowVar.void ShowVar( char *szTypes, ... );int main() { ShowVar( "fcsi", 32.4f, 'a', "Test string", 4 );}// ShowVar takes a format string of the form// "ifcs", where each character specifies the// type of the argument in that position.//// i = int// f = float// c = char// s = string (char *)//// Following the format specification is a variable // list of arguments. Each argument corresponds to // a format character in the format string to which // the szTypes parameter points void ShowVar( char *szTypes, ... ) { va_list vl; int i; // szTypes is the last argument specified; you must access // all others using the variable-argument macros. va_start( vl, szTypes ); // Step through the list. for( i = 0; szTypes[i] != '/0'; ++i ) { union Printable_t { int i; float f; char c; char *s; } Printable; switch( szTypes[i] ) { // Type to expect. case 'i': Printable.i = va_arg( vl, int ); printf_s( "%i/n", Printable.i ); break; case 'f': Printable.f = va_arg( vl, double ); printf_s( "%f/n", Printable.f ); break; case 'c': Printable.c = va_arg( vl, char ); printf_s( "%c/n", Printable.c ); break; case 's': Printable.s = va_arg( vl, char * ); printf_s( "%s/n", Printable.s ); break; default: break; } } va_end( vl );}//Output: // 32.400002// a// Test string
上一個示例演示以下重要概念:
在訪問任何變量參數前,必須建立一個列表標記作為類型 va_list 的變量。在前面的示例中,該標記稱為 vl。
使用 va_arg 宏訪問各個參數。必須告知 va_arg 宏要檢索的參數的類型,以便它可以從堆棧中傳輸正確的字節數。如果為 va_arg 指定的大小的類型與通過調用程序提供的類型不同,則結果是不可預知的。
應將使用 va_arg 宏獲取的結果顯式強制轉換為所需類型。
必須調用宏以終止可變參數處理。va_end
默認參數
在許多情況下,函數具有不常使用的參數,因為使用默認值便已足夠。為了解決此問題,默認參數工具允許為函數僅指定在給定調用中有意義的參數。為了闡釋此概念,請考慮函數重載中所示的示例。
// Prototype three print functions.int print( char *s ); // Print a string.int print( double dvalue ); // Print a double.int print( double dvalue, int prec ); // Print a double with a// given precision.
在許多應用程序中,可為 prec 提供合理的默認值,從而消除對兩個函數的需求:
// Prototype two print functions.int print( char *s ); // Print a string.int print( double dvalue, int prec=2 ); // Print a double with a// given precision.
略微更改了 print 函數的實現以反映類型 double 僅存在一個此類函數這一事實:
// default_arguments.cpp// compile with: /EHsc /c// Print a double in specified precision.// Positive numbers for precision indicate how many digits// precision after the decimal point to show. Negative// numbers for precision indicate where to round the number// to the left of the decimal point.#include <iostream>#include <math.h>using namespace std;int print( double dvalue, int prec ) { // Use table-lookup for rounding/truncation. static const double rgPow10[] = { 10E-7, 10E-6, 10E-5, 10E-4, 10E-3, 10E-2, 10E-1, 10E0, 10E1, 10E2, 10E3, 10E4, 10E5, 10E6 }; const int iPowZero = 6; // If precision out of range, just print the number. if( prec >= -6 && prec <= 7 ) // Scale, truncate, then rescale. dvalue = floor( dvalue / rgPow10[iPowZero - prec] ) * rgPow10[iPowZero - prec]; cout << dvalue << endl; return cout.good();}
若要調用新的 print 函數,請使用如下代碼:
print( d ); // Precision of 2 supplied by default argument.print( d, 0 ); // Override default argument to achieve other// results.
使用默認參數時,請注意以下幾點:
默認參數僅在其中省略了尾隨參數的函數調用中使用 - 它們必須是最后的參數。因此,以下代碼是非法的:
int print( double dvalue = 0.0, int prec );
默認參數不能在以后的聲明中重新定義,即使重新定義的參數與原始參數相同也是如此。因此,以下代碼將生成錯誤:
// Prototype for print function.int print( double dvalue, int prec = 2 );...// Definition for print function.int print( double dvalue, int prec = 2 ){...}
此代碼的問題在于定義中的函數聲明重新定義了 prec 的默認參數。
以后的聲明可添加額外的默認參數。
可為指向函數的指針提供默認參數。例如:
int (*pShowIntVal)( int i = 0 );