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

📄 effective c++ 2e item40.htm

📁 Effective-c++.国外很经典的一本关于c++编程的电子书。
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<DIV align=center>
<DIV class=fst align=left>
<DIV class=fstdiv3 id=print2><BR><BR>
<P>&nbsp;</P>
<P>条款40: 通过分层来体现 "有一个" 或 "用...来实现"</P>
<P>使某个类的对象成为另一个类的数据成员,从而实现将一个类构筑在另一个类之上,这一过程称为 "分层"(Layering)。例如:</P>
<P>class Address { ... 
};&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 某人居住之处</P>
<P>class PhoneNumber { ... };</P>
<P>class Person {<BR>public:<BR>&nbsp; ...</P>
<P>private:<BR>&nbsp; string 
name;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
// 下层对象<BR>&nbsp; Address 
address;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
// 同上<BR>&nbsp; PhoneNumber voiceNumber;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 
同上<BR>&nbsp; PhoneNumber 
faxNumber;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 同上<BR>};</P>
<P>本例中,Person类被认为是置于string,Address和PhoneNumber类的上层,因为它包含那些类型的数据成员。"分层" 
这一术语有很多同义词,它也常被称为:构成(composition),包含(containment)或嵌入(embedding)。</P>
<P>条款35解释了公有继承的含义是 "是一个"。对应地,分层的含义是 "有一个" 或 "用...来实现"。</P>
<P>上面的Person类展示了 "有一个" 的关系。一个Person对象 "有一个" 名字,地址,电话号码和传真号码。你不能说,一个人 "是一个" 
名字或一个人 "是一个" 地址;你得说,一个人 "有一个" 名字, "有一个" 地址,等等。大多数人对区分这些没什么困难,所以混淆 "是一个" 和 "有一个" 
的情况相对来说比较少见。</P>
<P>稍微有点麻烦的是区分 "是一个" 和 
"用...来实现"。例如,假设需要一个类模板,用来表示任意对象的集合,并且集合中没有重复元素。程序设计中,重用(Reuse)是再好不过的一件事了,而且你也许已经读过条款49中关于C++标准库的总体介绍,那么,你的第一反应一定是想采用标准库中的set模板。是啊,既然可以使用别人所写的东西,为什么还要再去写一个新的模板呢?</P>
<P>但是,深入研究set的帮助文档后,你会发现,set的下述限制将不能满足你的程序要求:set要求包含在它内部的元素必须是完全有序的,即,对set中的任两个元素a和b来说,一定可以确定:要么a&lt;b,要么b&lt;a。对许多类型来说,这个要求很容易满足,而且,对象间完全有序使得set可以在性能方面提供某些保证,这一点很吸引人。(参见条款49了解标准库在性能上更多的保证)然而,你所需要的是更广泛的东西:一个类似set的类,但对象不必完全有序;用C++标准所包装的术语来说,它们只需要所谓的 
"相等可比较性":对于同种类型的a和b对象来说,要能确定是否a==b。这种要求更简单,它更适合于那些表示颜色这类东西的类型。总不能说红色比绿色更少或绿色比红色更少吧?看来,对你的程序来说,还是得需要自己来写个模板。</P>
<P>当然,重用还是件好事。作为数据结构专家,你知道,在实现集合的众多选择中,一个最简单的办法是采用链表。你一定猜到了什么。对,标准库中正有这么一个list模板(用来产生链表类)!所以可以重用它。</P>
<P>具体来说,你决定让自己的Set模板从list继承。即,Set&lt;T&gt;将从list&lt;T&gt;继承。因为,在你的实现中,Set对象实际上将是list对象。于是你这样声明Set模板:</P>
<P>// Set中错误地使用了list<BR>template&lt;class T&gt;<BR>class Set: public 
list&lt;T&gt; { ... };</P>
<P>至此,一切好象都很正确,但实际上错误不小。正如条款35所说明的,如果D "是一个" 
B,对B成立的所有事实对D也成立。但是,list对象可以包含重复元素,所以如果3051这个值被增加到list&lt;int&gt;中两次,list中将包含3051的两个拷贝。相反,Set不可以包含重复元素,所以如果3051被增加到Set&lt;int&gt;中两次,Set中将只包含这个值的一个拷贝。于是,说一个Set 
"是一个" list就是弥天大谎,因为如上所述,有一些在list对象中成立的事实在Set对象中不成立。</P>
<P>因为这两个类的关系并非 "是一个",所以用公有继承来表示它们的关系就是一个错误。正确的方法是让Set对象 "用list对象来实现":</P>
<P>// Set中使用list的正确方法<BR>template&lt;class T&gt;<BR>class Set 
{<BR>public:<BR>&nbsp; bool member(const T&amp; item) const;</P>
<P>&nbsp; void insert(const T&amp; item);<BR>&nbsp; void remove(const T&amp; 
item);</P>
<P>&nbsp; int cardinality() const;</P>
<P>private:<BR>&nbsp; list&lt;T&gt; 
rep;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
// 表示一个Set<BR>};</P>
<P>Set的成员函数可以利用list以及标准库其它部分所提供的大量功能,所以,实现代码既不难写也很易读:</P>
<P>template&lt;class T&gt;<BR>bool Set&lt;T&gt;::member(const T&amp; item) 
const<BR>{ return find(rep.begin(), rep.end(), item) != rep.end(); }</P>
<P>template&lt;class T&gt;<BR>void Set&lt;T&gt;::insert(const T&amp; item)<BR>{ 
if (!member(item)) rep.push_back(item); }</P>
<P>template&lt;class T&gt;<BR>void Set&lt;T&gt;::remove(const T&amp; 
item)<BR>{<BR>&nbsp; list&lt;T&gt;::iterator it =<BR>&nbsp;&nbsp;&nbsp; 
find(rep.begin(), rep.end(), item);</P>
<P>&nbsp; if (it != rep.end()) rep.erase(it);<BR>}</P>
<P>template&lt;class T&gt;<BR>int Set&lt;T&gt;::cardinality() const<BR>{ return 
rep.size(); }</P>
<P>这些函数很简单,所以很自然地想到将它们作为内联函数;但在做最后决定前,还是回顾一下条款33所做的讨论。(上面的代码中,find, begin, end, 
push_back等函数是标准库基本框架的一部分,它们可用来对list这样的容器模板进行操作。标准库框架的总体介绍参见条款49和M35。)</P>
<P>值得指出的是,Set类的接口没有做到完整并且最小(参见条款18)。从完整性上来说,它最大的遗漏在于不能对Set中的内容进行循环,而这一功能对很多程序来说是必需的(标准库中的所有成员都提供了这一功能,包括set)。Set的另一个缺陷是没有遵循标准库所采用的容器类常规(见条款49和M35),从而造成使用Set时更难以利用库中其它的部分。</P>
<P>Set的接口尽管有这些瑕疵,但下面这一点不能被掩盖:Set在理解它和list的关系上,具有无可辩驳的正确性。这种关系并非 
"是一个"(虽然初看会以为是),而是 "用...来实现",通过分层来实现这种关系是类的设计者应该感到自豪的。</P>
<P>顺便说一句,当通过分层使两个类产生联系时,实际上在两个类之间建立了编译时的依赖关系。关于为什么要考虑到这一点以及如何减少这方面的麻烦,参见条款34。</P><BR><BR></DIV></DIV></DIV><BR><BR>
<SCRIPT src="Effective C++ 2e Item40.files/get_readnum.htm"></SCRIPT>

<TABLE cellSpacing=1 cellPadding=2 width=770 align=center bgColor=#666666 
border=0>
  <TBODY>
  <TR>
    <TH id=white bgColor=#990000><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 cellSpacing=1 cellPadding=2 width=770 align=center bgColor=#666666 
border=0>
  <TBODY>
  <TR>
    <TH id=white bgColor=#990000><FONT 
color=#ffffff>发表评论</FONT></TH></TR></TBODY></TABLE>
<TABLE cellSpacing=1 cellPadding=2 width=770 align=center bgColor=#ffffff 
border=0>
  <TBODY>
  <TR>
    <TD>
      <FORM name=add_critique action=/develop/add_critique.asp 
      method=post><INPUT type=hidden value=add name=critique_add> <INPUT 
      type=hidden value=9363 name=from> &nbsp;&nbsp;评论人: <INPUT name=csdnname> 
      &nbsp;&nbsp;密码: <INPUT type=password name=csdnpassword> 
      &nbsp;&nbsp;评论:<BR>&nbsp;&nbsp; <TEXTAREA name=critique_content rows=8 cols=100></TEXTAREA><BR>&nbsp;&nbsp; 
<INPUT onclick=javascript:submit1(); type=button value=发表评论 name=ubmit> 
      <INPUT type=hidden value=9363 name=id> </FORM></TD></TR></TBODY></TABLE>
<TABLE width=770 border=0>
  <TBODY>
  <TR>
    <TD>
      <TABLE cellPadding=2 width=770 border=0>
        <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 src="http://www.csdn.net/job/images/csdn_job.gif" 
            border=0></A> </TD>
          <TD align=middle width=510>
            <OBJECT id=Movie1 
            codeBase=http://active.macromedia.com/flash2/cabs/swflash.cab#version=4,0,0,0 
            height=60 width=468 
            classid=clsid:D27CDB6E-AE6D-11cf-96B8-444553540000><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 
            src="http://www.csdn.net/images/biaoshi.gif" border=0></A> 
        </TD></TR></TBODY></TABLE></TD></TR>
  <TR>
    <TD>
      <TABLE height=20 cellSpacing=0 cellPadding=0 width=770 align=default 
      bgColor=#1f60a0 border=0>
        <TBODY>
        <TR class=font13px vAlign=center align=middle>
          <TD class=font13px vAlign=center width=90 height=2></TD>
          <TD width=2 rowSpan=2><IMG height=13 
            src="http://www.csdn.net/images/ad4.gif" width=2></TD>
          <TD class=font13px width=90 height=2></TD>
          <TD width=3 rowSpan=2><FONT color=#ffffff><IMG height=13 
            src="http://www.csdn.net/images/ad4.gif" width=2></FONT></TD>
          <TD class=font13px width=90 height=2></TD>
          <TD width=2 rowSpan=2><IMG height=13 
            src="http://www.csdn.net/images/ad4.gif" width=2></TD>
          <TD class=font13px width=90 height=2></TD>
          <TD width=3 rowSpan=2><FONT color=#ffffff><IMG height=13 
            src="http://www.csdn.net/images/ad4.gif" width=2></FONT></TD>
          <TD width=350 height=2><FONT color=#ffffff></FONT></TD>
          <TD width=10 rowSpan=2><FONT color=#ffffff><IMG height=11 
            src="http://www.csdn.net/images/ad3.gif" width=6></FONT></TD>
          <TD class=font13px width=60 height=2></TD></TR>
        <TR class=font14px vAlign=center align=middle>
          <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 + -