⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 [10] constructors, c++ faq lite.htm

📁 c++faq。里面有很多关于c++的问题的解答。
💻 HTM
📖 第 1 页 / 共 4 页
字号:
<P>使用与<A 
href="http://www.sunistudio.com/cppfaq/ctors.html#[10.12]">描述过的相同的技巧</A>,但这次使用静态成员函数而不是全局函数而已。
<P>假设类 <TT>X </TT>有一个<TT>static</TT> <TT>Fred</TT>对象: 
<P>
<DIV 
class=CodeBlock><TT>&nbsp;</TT><EM>//&nbsp;File&nbsp;X.hpp</EM><TT><BR>&nbsp;<BR>&nbsp;class&nbsp;X&nbsp;{<BR>&nbsp;public:<BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...</EM><TT><BR>&nbsp;<BR>&nbsp;private:<BR>&nbsp;&nbsp;&nbsp;static&nbsp;Fred&nbsp;x_;<BR>&nbsp;}; 
</TT></DIV>
<P>自然的,该静态成员被分开初始化: 
<P>
<DIV 
class=CodeBlock><TT>&nbsp;</TT><EM>//&nbsp;File&nbsp;X.cpp</EM><TT><BR>&nbsp;<BR>&nbsp;#include&nbsp;"X.hpp"<BR>&nbsp;<BR>&nbsp;Fred&nbsp;X::x_; 
</TT></DIV>
<P>自然的,<TT>Fred</TT>对象会在 <TT>X </TT>的一个或多个方法中被使用: 
<P>
<DIV 
class=CodeBlock><TT>&nbsp;void&nbsp;X::someMethod()<BR>&nbsp;{<BR>&nbsp;&nbsp;&nbsp;x_.goBowling();<BR>&nbsp;} 
</TT></DIV>
<P>但现在“灾难情景”就是如果某人在某处不知何故在<TT>Fred</TT>对象被构造前调用这个方法。例如,如果某人在静态初始化期间创建一个静态的 <TT>X 
</TT>对象并调用它的<TT>someMethod()</TT>方法,然后你就受制于编译器是在<TT>someMethod()</TT>被调用之前或之后构造 
<TT>X::x_</TT>。(ANSI/ISO C++委员会正在设法解决这个问题,但诸多的编译器对处理这些更改一般还没有完成;关注此处将来的更新。)
<P>无论何种结果,将<TT>X::x_</TT> 静态数据成员改为静态成员函数总是最简便和安全的: 
<P>
<DIV 
class=CodeBlock><TT>&nbsp;</TT><EM>//&nbsp;File&nbsp;X.hpp</EM><TT><BR>&nbsp;<BR>&nbsp;class&nbsp;X&nbsp;{<BR>&nbsp;public:<BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...</EM><TT><BR>&nbsp;<BR>&nbsp;private:<BR>&nbsp;&nbsp;&nbsp;static&nbsp;Fred&amp;&nbsp;x();<BR>&nbsp;}; 
</TT></DIV>
<P>自然的,该静态成员被分开初始化: 
<P>
<DIV 
class=CodeBlock><TT>&nbsp;</TT><EM>//&nbsp;File&nbsp;X.cpp</EM><TT><BR>&nbsp;<BR>&nbsp;#include&nbsp;"X.hpp"<BR>&nbsp;<BR>&nbsp;Fred&amp;&nbsp;X::x()<BR>&nbsp;{<BR>&nbsp;&nbsp;&nbsp;static&nbsp;Fred*&nbsp;ans&nbsp;=&nbsp;new&nbsp;Fred();<BR>&nbsp;&nbsp;&nbsp;return&nbsp;*ans;<BR>&nbsp;} 
</TT></DIV>
<P>然后,简单地将 <TT>x_ </TT>改为 <TT>x()</TT>: 
<P>
<DIV 
class=CodeBlock><TT>&nbsp;void&nbsp;X::someMethod()<BR>&nbsp;{<BR>&nbsp;&nbsp;&nbsp;x().goBowling();<BR>&nbsp;} 
</TT></DIV>
<P>如果你对性能敏感并且关心每次调用<TT>X::someMethod()</TT>的额外的函数调用的开销,你可以设置一个<TT>static</TT> 
<TT>Fred&amp;</TT>来取代。正如你所记得的,静态局部对象仅被初始化一次(控制流程首次越过它们的声明处时),因此,将只调用<TT>X::x()</TT>一次:<TT>X::someMethod()</TT>首次被调用时:
<P> 
<DIV 
class=CodeBlock><TT>&nbsp;void&nbsp;X::someMethod()<BR>&nbsp;{<BR>&nbsp;&nbsp;&nbsp;static&nbsp;Fred&amp;&nbsp;x&nbsp;=&nbsp;X::x();<BR>&nbsp;&nbsp;&nbsp;x.goBowling();<BR>&nbsp;} 
</TT></DIV>
<P>注意:对于内建/固有类型,象<TT>int</TT> 或 
<TT>char*</TT>,不必这样做。例如,如果创建一个静态的或全局的<TT>float</TT>对象,不需要将它包裹于函数之中。静态初始化次序真正会崩溃的时机只有在你的<TT>static</TT>或全局对象有构造函数时。 

<P><SMALL>[&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/ctors.html#top">Top</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/ctors.html#bottom">Bottom</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/inline-functions.html">Previous&nbsp;section</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/dtors.html">Next&nbsp;section</A> 
]</SMALL> 
<HR>

<P><A name=[10.14]></A>
<DIV class=FaqTitle>
<H3>[10.14] 如何处理构造函数的失败?</H3></DIV>
<P>抛出一个异常。详见 <A 
href="http://www.sunistudio.com/cppfaq/exceptions.html#[17.2]">[17.2]</A>。 
<P><SMALL>[&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/ctors.html#top">Top</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/ctors.html#bottom">Bottom</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/inline-functions.html">Previous&nbsp;section</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/dtors.html">Next&nbsp;section</A> 
]</SMALL> 
<HR>

<P><A name=[10.15]></A>
<DIV class=FaqTitle>
<H3>[10.15] 什么是“命名参数用法(Named Parameter Idiom)”?<IMG alt=NEW! 
src="[10] Constructors, C++ FAQ Lite.files/new.gif"></H3></DIV><SMALL><EM>[Recently 
created (on 4/01). <A 
href="http://www.sunistudio.com/cppfaq/dtors.html#[11.13]">Click here to go to 
the next FAQ in the "chain" of recent 
changes<!--rawtext:[11.13]:rawtext--></A>.]</EM></SMALL> 
<P>发掘<A 
href="http://www.sunistudio.com/cppfaq/references.html#[8.4]">方法链</A>的非常有用的方法。
<P>命名参数用法(Named Parameter 
Idiom)解决的最基本问题是C++仅支持位置相关的参数。例如,函数调用者不能说“这个值给形参<TT>xyz</TT>,另一个值给形参<TT>pqr</TT>”。在C++(和C 
和Java)中只能说“这是第一个参数,这是第二个参数等”。Ada语言提出并实现的命名参数,对于带有大量的可缺省参数的函数尤其有用。
<P>多年来,人们构造了很多方案来弥补C 和 
C++缺乏的命名参数。其中包括将参数值隐藏于一个字符串参数,然后在运行时解析这个字符串。例如,这就是<TT>fopen()</TT>的第二个参数的做法。另一种方案是将所有的布尔参数联合成一个位映射,然后调用者将这堆转换成位的常量共同产生一个实际的参数。例如,这就是<TT>open()</TT>的第二个参数的做法。这些方法可以工作,但下面的技术产生的调用者的代码更明显,更容易写,更容易读,而且一般来说更雅致。
<P>这个想法,称为命名参数用法(Named Parameter 
Idiom),它是将函数的参数变为以新的方式创建的类的方法,这些方法通过引用返回<TT>*this</TT>。然后你只要将主要的函数改名为那个类中的无参数的“随意”方法。 

<P>举一个例子来解释上面那段。
<P>这个例子实现“打开一个文件”的概念。该概念逻辑上需要一个文件名的参数,和一些允许选择的参数,文件是否被只读或可读写或只写的方式打开;如果文件不存在,是否创建它;是从末尾写(添加"append")还是从起始处写(覆盖"overwrite");如果文件被创建,指定块大小; 
I/O是否有缓冲区,缓冲区大小;文件是被共享还是独占访问;以及其他可能的选项。如果我们用常规的位置相关的参数的函数实现这个概念,那么调用者的代码会非常难读:有8个可选的参数,并且调用者很可能犯错误。因此我们使用命名参数用法来取代。 

<P>在实现它之前,假如你想接受函数的所有默认参数,看一下调用者的代码是什么样子: 
<P> 
<DIV class=CodeBlock><TT>&nbsp;File&nbsp;f&nbsp;=&nbsp;OpenFile("foo.txt"); 
</TT></DIV>
<P>那是简单的情况。现在看一下如果你想改变一大堆的参数: 
<P>
<DIV 
class=CodeBlock><TT>&nbsp;File&nbsp;f&nbsp;=&nbsp;OpenFile("foo.txt").<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;readonly().<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;createIfNotExist().<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;appendWhenWriting().<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;blockSize(1024).<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unbuffered().<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exclusiveAccess(); 
</TT></DIV>
<P>注意这些“参数”,被公平的以随机的顺序(位置无关的)调用并且都有名字。因此,程序员不必记住参数的顺序,而且这些名字是(正如所希望的)意义明显的。
<P>以下是如何实现:首先创建一个新的类(<TT>OpenFile</TT>),该类包含了所有的参数值作为 <TT>private: 
</TT>数据成员。然后所有的方法(<TT>readonly()</TT>, <TT>blockSize(unsigned)</TT>, 
等)返回<TT>*this</TT>(也就是返回一个<TT>OpenFile</TT>对象的引用,以允许方法被<A 
href="http://www.sunistudio.com/cppfaq/references.html#[8.4]">链状</A>调用)。最后完成一个带有必要参数(在这里,就是文件名)的常规的,参数位置相关的<TT>OpenFile</TT>的构造函数。 

<P>
<DIV 
class=CodeBlock><TT>&nbsp;class&nbsp;File;<BR>&nbsp;<BR>&nbsp;class&nbsp;OpenFile&nbsp;{<BR>&nbsp;public:<BR>&nbsp;&nbsp;&nbsp;OpenFile(const&nbsp;string&amp;&nbsp;filename);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;为每个数据成员设置默认值</EM><TT><BR>&nbsp;&nbsp;&nbsp;OpenFile&amp;&nbsp;readonly();&nbsp;&nbsp;</TT><EM>//&nbsp;将&nbsp;<TT>readonly_</TT>&nbsp;变为&nbsp;<TT>true</TT></EM><TT><BR>&nbsp;&nbsp;&nbsp;OpenFile&amp;&nbsp;createIfNotExist();<BR>&nbsp;&nbsp;&nbsp;OpenFile&amp;&nbsp;blockSize(unsigned&nbsp;nbytes);<BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...</EM><TT><BR>&nbsp;private:<BR>&nbsp;&nbsp;&nbsp;friend&nbsp;File;<BR>&nbsp;&nbsp;&nbsp;bool&nbsp;readonly_;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;默认为&nbsp;<TT>false</TT>&nbsp;[举例]</EM><TT><BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...</EM><TT><BR>&nbsp;&nbsp;&nbsp;unsigned&nbsp;blockSize_;&nbsp;&nbsp;</TT><EM>//&nbsp;默认为 
4096&nbsp;[举例]</EM><TT><BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...</EM><TT><BR>&nbsp;}; 
</TT></DIV>
<P>要做的另外一件事就是使得 <TT>File</TT>的构造函数带一个<TT>OpenFile</TT>对象: 
<P>
<DIV 
class=CodeBlock><TT>&nbsp;class&nbsp;File&nbsp;{<BR>&nbsp;public:<BR>&nbsp;&nbsp;&nbsp;File(const&nbsp;OpenFile&amp;&nbsp;params);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;vacuums&nbsp;the&nbsp;actual&nbsp;params&nbsp;out&nbsp;of&nbsp;the&nbsp;OpenFile&nbsp;object</EM><TT><BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...</EM><TT><BR>&nbsp;}; 
</TT></DIV>
<P>注意<TT>OpenFile</TT> 将 <TT>File </TT>声明为<A 
href="http://www.sunistudio.com/cppfaq/friends.html">友元</A>,这样<A 
href="http://www.sunistudio.com/cppfaq/friends.html#[14.2]"><TT>OpenFile</TT> 
就不需要一大堆的(而且没用的)<TT>public:</TT> <EM>get</EM> 方法</A>。 
<P><SMALL>[&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/ctors.html#top">Top</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/ctors.html#bottom">Bottom</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/inline-functions.html">Previous&nbsp;section</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/dtors.html">Next&nbsp;section</A> 
]</SMALL> 
<HR>

<P><A name=bottom></A><A href="mailto:cline@parashift.com"><IMG height=26 
alt=E-Mail src="[10] Constructors, C++ FAQ Lite.files/mbox.gif" 
width=89>&nbsp;E-mail the author</A><BR>[&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/index.html"><EM>C++ FAQ Lite</EM></A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/index.html#table-of-contents">Table&nbsp;of&nbsp;contents</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/subject-index.html">Subject&nbsp;index</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/copy-permissions.html#[1.1]">About&nbsp;the&nbsp;author</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/copy-permissions.html#[1.2]">&copy;</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/on-line-availability.html#[2.2]">Download&nbsp;your&nbsp;own&nbsp;copy</A>&nbsp;]<BR><SMALL>Revised 
Apr 8, 2001</SMALL> </P></BODY></HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -