第二章 面向对象的编程风格(提供默认参数值)

 

2.3提供默认的参数值

 

在我们的冒泡排序的程序中,为了将跟踪信息打印到ofil,我必须让我希望加以调试的函数都能够使用ofil。我选择的方法是让许多函数都能够看到这个对象:换句话说,我在file scope中定义ofil是一个不受欢迎的举动。

一般程序编写法则是:以“参数传递”作为函数间的沟通方式。比“直接将对象定义于file scope”更适当。理由之一是,函数如果过于依赖定义于file scope内的对象,就比较难在其他环境中重用。也比较难以修改。我们不仅需要了解该函数的工作逻辑,也必须了解定义于file scope中的那些对象的工作逻辑。


程序:对bubble_sort()做修改,使他摆脱对file scope内ofil的依赖:

void bubble_sort(vector<int>&vec,ofstream &ofil)
{
 for(int ix=0;ix<vec.size();++ix)
 for(int jx=ix+1;jx<vec.size;++jx)
if(vec[ix]<vec[jx])
{
 ofil<<"about to call scope!ix:"<<ix
<<"jx:"<<jx<<"\tswapping:"<<vec[ix]<<"with"<<vec[jx]<<end1;
swap(vec[ix],vec[jx],ofil);

}
}


虽然这使我们摆脱了对file scope内ofil的依赖,但它也同时也带来了问题。每次调用bubble_sort()都必须传入一个ofstream对象,而且用户无法关闭我们所产生的信息。我们希望用户不但不必输出用的stream,而且有能力把输出信息关闭。默认情况下我们不想产生这些信息。但是我们又希望那些想要看到这些信息的用户可以产生它们。甚至指定其输出文件。于是:

程序改进:
c++允许我们全部或者部分参数设定默认值。本例中,我们的ofstream指针参数默认值为0:

void bubble_sort(vector<int>&vec,ofstream *ofil=0)
{
 for(int ix=0;ix<vec.size();++ix)
 for(int jx=ix+1;jx<vec.size();++jx)
 if(vec[ix]>vec[jx])
{
  if(ofil!=0)
  (*ofil)<<"about to call swap! ix:"<<ix
  <<"jx:"<<jx<<"\tswapping"
  <<vec[ix]<<"with"<<vec[jx]<<end1;
swap(vec[ix],vec[jx],ofil);

}
}

这个bubble_sort()将其第二参数声明为ofstream对象的一个pointer而非reference。我们必须做这样的一个改变,才可以设定它的默认值为0,表示并未指向任何ofstream对象。reference不同于pointer,无法被设置为0.因此reference一定得代表某个对象。

有了这样的改变后,当用户以单一参数调用bubble_sort()时,不会产生任何的调试信息。如果调用时有了第二参数,指向某个ofstream对象,那么这个函数会产生调试信息:程序


int main()
{
  int a[8]={8,32,3,13,1,21,5,2};
  vector<int>vec(ia,ia+8);
//以下就像调用bubble_sort(vec,0)一样
//不会产生任何调试信息
bubble_sort(vec);
display(vec);
//ok,这样会产生调试信息
ofstream ofil("data.txt");
bubble_sort(vec,&ofil);
display(vec,ofil);
}
display()的实现呈现出另一种情况,到目前为止,display()仍将输出写死到cout身上。一般情况下输出到cout当然很好,但是有时候用户希望提供一个不同的目的地,例如文件。我们必须能够在main()之中同时支持这两种使用方法。解决之道就是要cout成为默认的ostream参数:

void display(const vector<int>&vec,ostream&os=cout)
{
for(int ix=0;ix<vec.size;ix++)
os<<vec[ix]<<' ';
os<<end1;
}

关于默认提供有两个不很直观的规则,第一个规则是,默认值的解析操作由最右边开始。如果我们为某个参数提供了默认值,那么这一参数右侧的所有参数必须也具有默认参值才可以。下面这样就是非法:
void display(ostream &os=cout,const vector<int>&vec);//os的值没有默认

第二个规则:默认值只能使用一次,可以在函数的声明处,也可以在函数的定义处。但不能再同时。那么,我们应该在何处指定参数的默认值呢?
通常,函数的声明会被放在头文件,每个打算使用函数的文件,都会包含对应的头文件。例如,我们包含cstdlib头文件时为了包含exit()函数声明。函数的定义通常被放在程序的代码文件,该文件只被编译一次,当我们使用该函数时,会将它链接link到我们的程序来。也就是说:头文件为函数带来更高的可见性visibility。

程序:为了更高的可见性,我们将默认放在函数的声明而非定义处。因此display()的声明和定义通常是这样的:
//头文件声明,其中指定参数的默认值
//我们称此头文件为numericseq.h
void display(const vector<int>&,ostream&=cout);
//程序代码包含上述头文件
//至于函数的定义处,并没有指定函数的默认值
#include"numericseq.h"
void display(const vector<int>&vec,ostream &os)
{
  for(int ix;ix<vec,size;++ix)
  os<<vec[ix]<<' ';
  os<<end1;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值