C++的命名参数惯用法(Named Parameter Idiom)

命名参数惯用法(Named Parameter Idiom)解决的问题是:C++函数参数有位置次序性的限制(positional parameters),也就是说,调用C++函数时,你不能只提供几个参数而已,而且你还要提供这几个参数的次序信息,这一点C++不如Ada 编译器内置就提供命名参数(named  parameters)功能,这个功能对于实现大量参数的函数,尤其是大量默认参数的函数特别有用「译者:因为参数量大的函数会给调用函数的程序员带来不便」。
       多年以来,人们发明了很多方法来弥补这个C++的不足,其中之一就是把参数转储到一个字符串中,然后在运行期再把参数给抽取出来,例如fopen的第二个参数。还有个比较特殊的例子是,把若干个bool参数,放到一个位表(bit-map)中,然后调用时再通过位移来获取原来的参数,例如open函数的第二个参数。这些方法都是为了解决了量大参数函数的问题。但是下面要介绍的命名参数惯用法能更加优雅方便得解决这个问题。
       用一句话概况命名参数惯用法,就是把函数参数换成此类的另一个方法,所有这样的方法都返回*this,也就是自己的引用,然后把原来函数的参数全部去掉,变成了一个方法「译者:定义有参数的方法(Method)叫函数(Function)」。
       下面举一个用于打开文件的类的实例来说明:
        打开一个文件需要文件路径字符串,还有很多可选参数:文件的读写性、文件不存在是否自动创建一个、写文件的位置是文件首端还是末端、创建文件的大小、是否需要IO缓冲区、缓冲区大小、是否能被共享访问,等等...很多。如果按照常规去实现这样一个函数的话,那么代码非常难以阅读,长达8个限制位置次序的参数,使得调用的程序员很容易搞错。所以我们要使用Named Parameter Idiom。
       在实现之前,我们先看看实现的结果是怎样的。使用默认参数的情况下,看起来像这样:

File f  =  OpenFile( " foo.txt " );

       如果要指定一串参数,那么就像这样:

File f  =  OpenFile( " foo.txt " )
            .
readonly ()
            .createIfNotExist()
            .appendWhenWriting()
            .blockSize(
1024 )
            .unbuffered()
            .exclusiveAccess();
      
       这样的话我们可以随便改变这些"参数"的次序(not positional),而且他们都有了可读性较强的名子。
       如何来实现呢?首先我们要创建一个OpenFile类,为所有用到的参数建立他们相对应的OpenFile私有数据成员。唯一一个文件路径的参数仍然用传统方式,放在OpenFile的构造函数上,但构造函数并不真正去打开文件。而所有其他的可选参数,都变成了方法,这些方法(如,readonly(),blockSize(unsigned)等),都返回一个OpenFile自身的引用,使得这些方法能够被链式调用(chained)。

class  File;
 
 
class  OpenFile  {
 
public:
   OpenFile(
const std::string& filename);
     
// sets all the default values for each data member
   OpenFile& readonly();  // changes readonly_ to true
   OpenFile& readwrite(); // changes readonly_ to false
   OpenFile& createIfNotExist();
   OpenFile
& blockSize(unsigned nbytes);
   ...
 
private:
   friend 
class File;
   std::
string filename_;
   
bool readonly_;          // defaults to false [for example]
   bool createIfNotExist_;  // defaults to false [for example]
   ...
   unsigned blockSize_;     
// defaults to 4096 [for example]
   ...
 }
;
 
 inline OpenFile::OpenFile(
const  std:: string &  filename)
   : filename_         (filename)
   , readonly_         (
false )
   , createIfNotExist_ (
false )
   , blockSize_        (
4096u )
 
{ }
 
 inline OpenFile
&  OpenFile:: readonly ()
 
{ readonly_ = truereturn *this; }
 
 inline OpenFile
&  OpenFile::readwrite()
 
{ readonly_ = falsereturn *this; }
 
 inline OpenFile
&  OpenFile::createIfNotExist()
 
{ createIfNotExist_ = truereturn *this; }
 
 inline OpenFile
&  OpenFile::blockSize(unsigned nbytes)
 
{ blockSize_ = nbytes; return *this; }

另外建立一个File类来接收一个OpenFile对像:

  class  File {
 
public :
   File(
const  OpenFile &   params );
   ...
 };

这个类的构造函数来获取所有的参数,来真正打开文件:

File::File( const  OpenFile &   params )
 {
   ...
 }

注意OpenFile类已经声明了File是它的友元,这样可以方便File获取他的私有成员。
那个链式的方法调用都是使用引用方式,所以没有对象拷贝的开销,效率很高,如果还是inline的,那么就和C差不多高效了。

原文: http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.18
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值