📄 effective c++ 2e item24.htm
字号:
<P>会对函数重载和设定参数缺省值产生混淆的原因在于,它们都允许一个函数以多种方式被调用:</P>
<P>void
f();
// f被重载<BR>void f(int x);</P>
<P>f();
//
调用f()<BR>f(10);
// 调用f(int)</P>
<P>void g(int x =
0);
// g
有一个<BR>
// 缺省参数值</P>
<P>g();
//
调用g(0)<BR>g(10);
// 调用g(10)</P>
<P>那么,什么时候该用哪种方法呢?</P>
<P>答案取决于另外两个问题。第一,确实有那么一个值可以作为缺省吗?第二,要用到多少种算法?一般来说,如果可以选择一个合适的缺省值并且只是用到一种算法,就使用缺省参数(参见条款38)。否则,就使用函数重载。</P>
<P>下面是一个最多可以计算五个int的最大值的函数。这个函数使用了——深呼一口气,看清楚啦——std::numeric_limits<int>::min(),作为缺省参数值。等会儿再进一步介绍这个值,这里先给出函数的代码:</P>
<P>int max(int a,<BR> int b =
std::numeric_limits<int>::min(),<BR>
int c =
std::numeric_limits<int>::min(),<BR>
int d =
std::numeric_limits<int>::min(),<BR>
int e = std::numeric_limits<int>::min())<BR>{<BR> int temp = a >
b ? a : b;<BR> temp = temp > c ? temp : c;<BR> temp = temp > d
? temp : d;<BR> return temp > e ? temp : e;<BR>}</P>
<P>现在可以放松了。std::numeric_limits<int>::min()是C++标准库用一种特有的新方法所表示的一个在C里已经定义了的东西,即C在<limits.h>中定义的INT_MIN宏所表示的那个东西——处理你的C++原代码的编译器所产生的int的最小可能值。是的,它的句法背离了C所具有的简洁,但在那些冒号以及其它奇怪的句法背后,是有道理可循的。</P>
<P>假设想写一个函数模板,其参数为固定数字类型,模板产生的函数可以打印用“实例化类型”表示的最小值。这个模板可以这么写:</P>
<P>template<class T><BR>void printMinimumValue()<BR>{<BR> cout
<< 表示为T类型的最小值;<BR>}</P>
<P>如果只是借助<limits.h>和<float.h>来写这个函数会觉得很困难,因为不知道T是什么,所以不知道该打印INT_MIN还是DBL_MIN,或其它什么类型的值。</P>
<P>为避开这些困难,标准C++库(见条款49)在头文件<limits>
中定义了一个类模板numeric_limits,这个类模板本身也定义了一些静态成员函数。每个函数返回的是“实例化这个模板的类型”的信息。也就是说,numeric_limits<int>中的函数返回的信息是关于类型int的,numeric_limits<double>
中的函数返回的信息是关于类型double的。numeric_limits中有一个函数叫min,min返回可表示为“实例化类型”的最小值,所以numeric_limits<int>::min()返回的是代表整数类型的最小值。</P>
<P>有了numeric_limits(和标准库中其它东西一样,numeric_limits存在于名字空间std中;numeric_limits本身在头文件<limits>中),写printMinimumValue就可以象下面这样容易:</P>
<P>template<class T><BR>void printMinimumValue()<BR>{<BR> cout
<< std::numeric_limits<T>::min();<BR>}</P>
<P>采用基于numeric_limits的方法来表示“类型相关常量”看起来开销很大,其实不然。因为原代码的冗长的语句不会反映到生成的目标代码中。实际上,对numeric_limits的调用根本就不产生任何指令。想知道怎么回事,看看下面,这是numeric_limits<int>::min的一个很简单的实现:</P>
<P>#include <limits.h></P>
<P>namespace std {</P>
<P> inline int numeric_limits<int>::min() throw ()<BR> {
return INT_MIN; }</P>
<P>}</P>
<P>因为此函数声明为inline,对它的调用会被函数体代替(见条款33)。它只是个INT_MIN,也就是说,它本身仅仅是个简单的“实现时定义的常量”的#define。所以即使本条款开头的那个max函数看起来好象对每个缺省参数进行了函数调用,其实只不过是用了另一种聪明的方法来表示一个类型相关常量而已(本例中常量值为INT_MIN)。象这样一些高效巧妙的应用在C++标准库里俯拾皆是,这可以参考条款49。</P>
<P>回到max
函数上来:最关键的一点是,不管函数的调用者提供几个参数,max计算时采用的是相同(效率很低)的算法。在函数内部任何地方都不用在意哪些参数是“真”的,哪些是缺省值;而且,所选用的缺省值不可能影响到所采用的算法计算的正确性。这就是使用缺省参数值的方案可行的原因。</P>
<P>对很多函数来说,会找不到合适的缺省值。例如,假设想写一个函数来计算最多可达5个int的平均值。这里就不能用缺省参数,因为函数的结果取决于传入的参数的个数:如果传入3个值,就要将总数除以3;如果传入5个值,就要将总数除以5。另外,假如用户没有提供某个参数时,没有一个“神奇的数字”可以作为缺省值,因为所有可能的int都可以是有效参数。这种情况下就别无选择:必须重载函数:</P>
<P>double avg(int a);<BR>double avg(int a, int b);<BR>double avg(int a, int b,
int c);<BR>double avg(int a, int b, int c, int d);<BR>double avg(int a, int b,
int c, int d, int e);</P>
<P>另一种必须使用重载函数的情况是:想完成一项特殊的任务,但算法取决于给定的输入值。这种情况对于构造函数很常见:“缺省”构造函数是凭空(没有输入)构造一个对象,而拷贝构造函数是根据一个已存在的对象构造一个对象:</P>
<P>// 一个表示自然数的类<BR>class Natural {<BR>public:<BR> Natural(int
initValue);<BR> Natural(const Natural& rhs);</P>
<P>private:<BR> unsigned int value;</P>
<P> void init(int initValue);<BR> void error(const string&
msg);<BR>};</P>
<P>inline<BR>void Natural::init(int initValue) { value = initValue; }</P>
<P>Natural::Natural(int initValue)<BR>{<BR> if (initValue > 0)
init(initValue);<BR> else error("Illegal initial value");<BR>}</P>
<P>inline Natural::Natural(const Natural& x)<BR>{ init(x.value); }</P>
<P>输入为int的构造函数必须执行错误检查,而拷贝构造函数不需要,所以需要两个不同的函数来实现,这就是重载。还请注意,两个函数都必须对新对象赋一个初值。这会导致在两个构造函数里出现重复代码,所以要写一个“包含有两个构造函数公共代码”的私有成员函数init来解决这个问题。这个方法——在重载函数中调用一个“为重载函数完成某些功能”的公共的底层函数——很值得牢记,因为它经常有用(见条款12)。</P><BR><BR></DIV></DIV></DIV><BR><BR>
<SCRIPT src="Effective C++ 2e Item24.files/get_readnum.htm"></SCRIPT>
<TABLE align=center bgColor=#666666 border=0 cellPadding=2 cellSpacing=1
width=770>
<TBODY>
<TR>
<TH bgColor=#990000 id=white><FONT
color=#ffffff>对该文的评论</FONT></TH></TR></TBODY></TABLE><BR>
<SCRIPT language=javascript>
<!--
function isEmpty(s)
{
return ((s == null) || (s.length == 0))
}
function submit1()
{
if (isEmpty(document.add_critique.csdnname.value) || isEmpty(document.add_critique.csdnpassword.value) || isEmpty(document.add_critique.critique_content.value))
{
alert('登陆名,密码,评论不能为空!!!!') ;
return false;
}
document.add_critique.submit();
}
//-->
</SCRIPT>
<TABLE align=center bgColor=#666666 border=0 cellPadding=2 cellSpacing=1
width=770>
<TBODY>
<TR>
<TH bgColor=#990000 id=white><FONT
color=#ffffff>发表评论</FONT></TH></TR></TBODY></TABLE>
<TABLE align=center bgColor=#ffffff border=0 cellPadding=2 cellSpacing=1
width=770>
<TBODY>
<TR>
<TD>
<FORM action=/develop/add_critique.asp method=post
name=add_critique><INPUT name=critique_add type=hidden value=add> <INPUT
name=from type=hidden value=8859> 评论人: <INPUT name=csdnname>
密码: <INPUT name=csdnpassword type=password>
评论:<BR> <TEXTAREA cols=100 name=critique_content rows=8></TEXTAREA><BR>
<INPUT name=ubmit onclick=javascript:submit1(); type=button value=发表评论>
<INPUT name=id type=hidden value=8859> </FORM></TD></TR></TBODY></TABLE>
<TABLE border=0 width=770>
<TBODY>
<TR>
<TD>
<TABLE border=0 cellPadding=2 width=770>
<TBODY>
<TR>
<TD height=10></TD></TR>
<TR>
<TD align=left width=130><A
href="http://www.csdn.net/news/looknews.asp?id=2313"
target=_blank><IMG border=0
src="http://www.csdn.net/job/images/csdn_job.gif"></A> </TD>
<TD align=middle width=510>
<OBJECT classid=clsid:D27CDB6E-AE6D-11cf-96B8-444553540000
codeBase=http://active.macromedia.com/flash2/cabs/swflash.cab#version=4,0,0,0
height=60 id=Movie1 width=468><PARAM NAME="movie" VALUE="http://www.csdn.net/images/ad/csdn_media.swf"><PARAM NAME="quality" VALUE="high">
<EMBED src="http://www.csdn.net/images/ad/csdn_media.swf"
quality=high WIDTH=468 HEIGHT=60
TYPE="application/x-shockwave-flash"
PLUGINSPAGE="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash">
</EMBED> </OBJECT></TD>
<TD align=middle width=130><A
href="http://www.hd315.gov.cn/beian/view.asp?bianhao=010202001032100010"><IMG
border=0 src="http://www.csdn.net/images/biaoshi.gif"></A>
</TD></TR></TBODY></TABLE></TD></TR>
<TR>
<TD>
<TABLE align=default bgColor=#1f60a0 border=0 cellPadding=0 cellSpacing=0
height=20 width=770>
<TBODY>
<TR align=middle class=font13px vAlign=center>
<TD class=font13px height=2 vAlign=center width=90></TD>
<TD rowSpan=2 width=2><IMG height=13
src="http://www.csdn.net/images/ad4.gif" width=2></TD>
<TD class=font13px height=2 width=90></TD>
<TD rowSpan=2 width=3><FONT color=#ffffff><IMG height=13
src="http://www.csdn.net/images/ad4.gif" width=2></FONT></TD>
<TD class=font13px height=2 width=90></TD>
<TD rowSpan=2 width=2><IMG height=13
src="http://www.csdn.net/images/ad4.gif" width=2></TD>
<TD class=font13px height=2 width=90></TD>
<TD rowSpan=2 width=3><FONT color=#ffffff><IMG height=13
src="http://www.csdn.net/images/ad4.gif" width=2></FONT></TD>
<TD height=2 width=350><FONT color=#ffffff></FONT></TD>
<TD rowSpan=2 width=10><FONT color=#ffffff><IMG height=11
src="http://www.csdn.net/images/ad3.gif" width=6></FONT></TD>
<TD class=font13px height=2 width=60></TD></TR>
<TR align=middle class=font14px vAlign=center>
<TD class=font13px vAlign=center width=90><A
href="http://www.csdn.net/intro/intro.shtm"><FONT
color=#ffffff>美达美简介</FONT></A></TD>
<TD class=font13px width=90><A
href="http://www.csdn.net/intro/ad.shtm"><FONT
color=#ffffff>广告服务</FONT></A></TD>
<TD class=font13px width=90><A
href="http://www.csdn.net/English/"><FONT
color=#ffffff>英语步步高</FONT></A></TD>
<TD class=font13px width=90><A href="http://www.csdn.net/dev/"><FONT
color=#ffffff>程序员大本营</FONT></A></TD>
<TD align=right width=350><SPAN class=font13px><A
href="mailto:webmaster@csdn.net"><FONT
color=#ffffff>百联美达美科技有限公司</FONT></A></SPAN><FONT color=#ffffff><SPAN
class=font13px> </SPAN></FONT></TD>
<TD class=font13px width=60><FONT color=#ffffff>版权所有</FONT>
<SCRIPT>document.write("<img src=http://202.106.156.10/stat.asp?user=designol&refer="+escape(document.referrer)+"&cur="+escape(document.URL)+" width=0 height=0 border=0>");</SCRIPT>
</TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></CENTER></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -