实例讲解在C++的函数中变量参数及默认参数的使用
包含变量参数列表的函数
如果函数声明中最后一个成员是省略号(...),则函数声明可采用数量可变的参数。在这些情况下,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,butnotdefinition,ofShowVar.
voidShowVar(char*szTypes,...);
intmain(){
ShowVar("fcsi",32.4f,'a',"Teststring",4);
}
//ShowVartakesaformatstringoftheform
//"ifcs",whereeachcharacterspecifiesthe
//typeoftheargumentinthatposition.
//
//i=int
//f=float
//c=char
//s=string(char*)
//
//Followingtheformatspecificationisavariable
//listofarguments.Eachargumentcorrespondsto
//aformatcharacterintheformatstringtowhich
//theszTypesparameterpoints
voidShowVar(char*szTypes,...){
va_listvl;
inti;
//szTypesisthelastargumentspecified;youmustaccess
//allothersusingthevariable-argumentmacros.
va_start(vl,szTypes);
//Stepthroughthelist.
for(i=0;szTypes[i]!='\0';++i){
unionPrintable_t{
inti;
floatf;
charc;
char*s;
}Printable;
switch(szTypes[i]){//Typetoexpect.
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
//Teststring
上一个示例演示以下重要概念:
在访问任何变量参数前,必须建立一个列表标记作为类型va_list的变量。在前面的示例中,该标记称为vl。
使用va_arg宏访问各个参数。必须告知va_arg宏要检索的参数的类型,以便它可以从堆栈中传输正确的字节数。如果为va_arg指定的大小的类型与通过调用程序提供的类型不同,则结果是不可预知的。
应将使用va_arg宏获取的结果显式强制转换为所需类型。
必须调用宏以终止可变参数处理。va_end
默认参数
在许多情况下,函数具有不常使用的参数,因为使用默认值便已足够。为了解决此问题,默认参数工具允许为函数仅指定在给定调用中有意义的参数。为了阐释此概念,请考虑函数重载中所示的示例。
//Prototypethreeprintfunctions. intprint(char*s);//Printastring. intprint(doubledvalue);//Printadouble. intprint(doubledvalue,intprec);//Printadoublewitha //givenprecision.
在许多应用程序中,可为prec提供合理的默认值,从而消除对两个函数的需求:
//Prototypetwoprintfunctions. intprint(char*s);//Printastring. intprint(doubledvalue,intprec=2);//Printadoublewitha //givenprecision.
略微更改了print函数的实现以反映类型double仅存在一个此类函数这一事实:
//default_arguments.cpp
//compilewith:/EHsc/c
//Printadoubleinspecifiedprecision.
//Positivenumbersforprecisionindicatehowmanydigits
//precisionafterthedecimalpointtoshow.Negative
//numbersforprecisionindicatewheretoroundthenumber
//totheleftofthedecimalpoint.
#include<iostream>
#include<math.h>
usingnamespacestd;
intprint(doubledvalue,intprec){
//Usetable-lookupforrounding/truncation.
staticconstdoublergPow10[]={
10E-7,10E-6,10E-5,10E-4,10E-3,10E-2,10E-1,10E0,
10E1,10E2,10E3,10E4,10E5,10E6
};
constintiPowZero=6;
//Ifprecisionoutofrange,justprintthenumber.
if(prec>=-6&&prec<=7)
//Scale,truncate,thenrescale.
dvalue=floor(dvalue/rgPow10[iPowZero-prec])*
rgPow10[iPowZero-prec];
cout<<dvalue<<endl;
returncout.good();
}
若要调用新的print函数,请使用如下代码:
print(d);//Precisionof2suppliedbydefaultargument. print(d,0);//Overridedefaultargumenttoachieveother //results.
使用默认参数时,请注意以下几点:
默认参数仅在其中省略了尾随参数的函数调用中使用-它们必须是最后的参数。因此,以下代码是非法的:
intprint(doubledvalue=0.0,intprec);
默认参数不能在以后的声明中重新定义,即使重新定义的参数与原始参数相同也是如此。因此,以下代码将生成错误:
//Prototypeforprintfunction.
intprint(doubledvalue,intprec=2);
...
//Definitionforprintfunction.
intprint(doubledvalue,intprec=2)
{
...
}
此代码的问题在于定义中的函数声明重新定义了prec的默认参数。
以后的声明可添加额外的默认参数。
可为指向函数的指针提供默认参数。例如:
int(*pShowIntVal)(inti=0);