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

📄 mi25.htm

📁 一个非常适合初学者入门的有关c++的文档
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN" "http://www.w3.org/TR/REC-html40/frameset.dtd">
<HTML LANG="EN">
<HEAD>
<TITLE>More Effective C++ | Item 25: Virtualizing constructors and non-member functions</TITLE>
<LINK REL=STYLESHEET HREF=../INTRO/ECMEC.CSS>

<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/COOKIE.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript">var imagemax = 2; setCurrentMax(2);</SCRIPT>
<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/IMGDOC.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/NSIMGDOC.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/DINGBATS.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript">var dingbase = "MI25_DIR.HTM"; var dingtext = "Item M25, P"; if (self == top) {
 top.location.replace(dingbase + this.location.hash);
}</SCRIPT>

</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" ONLOAD="setResize()">
<!-- SectionName="M25: Virtualizing ctors and non-member functions" -->
<A NAME="5341"></A>
<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./MTECH_FR.HTM" TARGET="_top">Techniques</A> &nbsp;&nbsp;<BR>&nbsp;&nbsp;Continue to <A HREF="./MI26_FR.HTM" TARGET="_top">Item 26: Limiting the number of objects of a class</A></FONT></DIV>


<P><A NAME="dingp1"></A><font ID="mititle">Item 25: &nbsp;Virtualizing constructors and non-member functions.</font><SCRIPT>create_link(1);</SCRIPT>
</P>

<A NAME="72164"></A><A NAME="11237"></A>

<P><A NAME="dingp2"></A>
On the face of it, it doesn't make much sense to talk about "virtual constructors." You call a virtual function to achieve type-specific behavior <A NAME="p124"></A>when you have a pointer or reference to an object but you don't know what the real type of the object is. You call a constructor only when you don't yet have an object but you know exactly what type you'd like to have. How, then, can one talk of <I>virtual</I> <NOBR>constructors?<SCRIPT>create_link(2);</SCRIPT>
</NOBR></P><A NAME="11236"></A>
<P><A NAME="dingp3"></A>
It's easy. Though virtual constructors may seem nonsensical, they are remarkably useful. (If you think nonsensical ideas are never useful, how do you explain the success of modern physics?) For example, suppose you write applications for working with newsletters, where a newsletter consists of components that are either textual or graphical. You might organize things this <NOBR>way:<SCRIPT>create_link(3);</SCRIPT>
</NOBR></P>
<A NAME="61094"></A>
<UL><PRE>
class NLComponent {               // abstract base class for
public:                           // newsletter components
<A NAME="61124"></A>
  ...                             // contains at least one
};                                // pure virtual function
<A NAME="61095"></A>
class TextBlock: public NLComponent {
public:
  ...                             // contains no pure virtual
};                                // functions
<A NAME="62249"></A>
class Graphic: public NLComponent {
public:
  ...                             // contains no pure virtual
};                                // functions
<A NAME="70590"></A>
class NewsLetter {                // a newsletter object
public:                           // consists of a list of
  ...                             // NLComponent objects
<A NAME="70591"></A>
private:
  list&lt;NLComponent*&gt; components;
};
</PRE>
</UL>

<A NAME="61229"></A>
<P><A NAME="dingp4"></A>
The classes relate in this <NOBR>way:<SCRIPT>create_link(4);</SCRIPT>
</NOBR></P>
<BR><BR>
<SPAN ID="Image1of1" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_124A1.GIF" BORDER=0></SPAN>
<SPAN ID="Image1of2" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_124A2.GIF" BORDER=0></SPAN>
<SPAN ID="Image1of3" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_124A3.GIF" BORDER=0></SPAN>
<SPAN ID="Image1of4" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_124A4.GIF" BORDER=0></SPAN>
<SPAN ID="Image1of5" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_124A5.GIF" BORDER=0></SPAN>

<SPAN ID="Image1of6" STYLE="position: relative; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_124A5.GIF" BORDER=0></SPAN>
<BR><BR>

<A NAME="61228"></A>
<P><A NAME="dingp5"></A>
The <CODE>list</CODE> class used inside <CODE>NewsLetter</CODE> is part of the Standard Template Library, which is part of the standard C++ library (see <a href="../EC/EI49_FR.HTM#8392" TARGET="_top">Item E49</A> <A NAME="p125"></A>and <a href="./MI35_FR.HTM#5473" TARGET="_top">Item 35</A>). Objects of type <CODE>list</CODE> behave like doubly linked lists, though they need not be implemented in that <NOBR>way.<SCRIPT>create_link(5);</SCRIPT>
</NOBR></P><A NAME="61274"></A>
<P><A NAME="dingp6"></A>
<CODE>NewsLetter</CODE> objects, when not being worked on, would likely be stored on disk. To support the creation of a <CODE>Newsletter</CODE> from its on-disk representation, it would be convenient to give <CODE>NewsLetter</CODE> a constructor that takes an <CODE>istream</CODE>. The constructor would read information from the stream as it created the necessary in-core data <NOBR>structures:<SCRIPT>create_link(6);</SCRIPT>
</NOBR></P>

<A NAME="61287"></A>
<UL><PRE>class NewsLetter {
public:
  NewsLetter(istream&amp; str);
  ...
};
</PRE>
</UL>

<A NAME="61299"></A>
<P><A NAME="dingp7"></A>
Pseudocode for this constructor might look like <NOBR>this,<SCRIPT>create_link(7);</SCRIPT>
</NOBR></P>

<A NAME="61300"></A>
<UL><PRE>NewsLetter::NewsLetter(istream&amp; str)
{
  while (str) {
    <I>read the next component object from str;</I>
<A NAME="61308"></A>
    <I>add the object to the list of this
    newsletter's components;</I>
  }
}
</PRE>
</UL>

<A NAME="61302"></A><P><A NAME="dingp8"></A>
or, after moving the tricky stuff into a separate function called <CODE>readComponent</CODE>, like <NOBR>this:<SCRIPT>create_link(8);</SCRIPT>
</NOBR></P>

<A NAME="61390"></A>
<UL><PRE>class NewsLetter {
public:
  ...
<A NAME="61397"></A>
private:
  // read the data for the next NLComponent from str,
  // create the component and return a pointer to it
  static NLComponent * readComponent(istream&amp; str);
  ...
};
<A NAME="61342"></A>
NewsLetter::NewsLetter(istream&amp; str)
{
  while (str) {
    // add the pointer returned by readComponent to the
    // end of the components list; "push_back" is a list
    // member function that inserts at the end of the list
    components.push_back(readComponent(str));
  }
}
</PRE>
</UL>

<A NAME="61328"></A>
<P><A NAME="dingp9"></A>
Consider what <CODE>readComponent</CODE> does. It creates a new object, either a <CODE>TextBlock</CODE> or a <CODE>Graphic</CODE>, depending on the data it reads. Because it <A NAME="p126"></A>creates new objects, it acts much like a constructor, but because it can create different types of objects, we call it a <I>virtual constructor</I>. A virtual constructor is a function that creates different types of objects depending on the input it is given. Virtual constructors are useful in many contexts, only one of which is reading object information from disk (or off a network connection or from a tape, <NOBR>etc.).<SCRIPT>create_link(9);</SCRIPT>
</NOBR></P><A NAME="61377"></A>
<P><A NAME="dingp10"></A>
A particular kind of virtual constructor &#151; the <I>virtual copy constructor</I> &#151; is also widely useful. A virtual copy constructor returns a pointer to a new copy of the object invoking the function. Because of this behavior, virtual copy constructors are typically given names like <CODE>copySelf</CODE>, <CODE>cloneSelf</CODE>, or, as shown below, just plain <CODE>clone</CODE>. Few functions are implemented in a more straightforward <NOBR>manner:<SCRIPT>create_link(10);</SCRIPT>
</NOBR></P>

<A NAME="61421"></A>
<UL><PRE>class NLComponent {
public:
  // declaration of virtual copy constructor
  virtual NLComponent * clone() const = 0;
  ...
<A NAME="75507"></A>
};
<A NAME="61423"></A>
class TextBlock: public NLComponent {
public:
  virtual TextBlock * clone() const         // virtual copy
  { return new TextBlock(*this); }          // constructor
  ...

⌨️ 快捷键说明

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