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

📄 ei45.htm

📁 一个非常适合初学者入门的有关c++的文档
💻 HTM
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN" "http://www.w3.org/TR/REC-html40/frameset.dtd">
<HTML LANG="EN">
<HEAD>
<title>Effective C++, 2E | Item 45: Know what functions C++ silently writes and calls</TITLE>
<LINK REL=STYLESHEET HREF=../INTRO/ECMEC.CSS>

<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/COOKIE.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript">var imagemax = 0; setCurrentMax(0);</SCRIPT>
<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/DINGBATS.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript">
var dingbase = "EI45_DIR.HTM";
var dingtext = "Item E45, P";
if (self == top) {
 top.location.replace(dingbase + this.location.hash);
}
</SCRIPT>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" ONLOAD="setResize()">
<!-- SectionName="E45: Know the implicitly generated functions" -->
<A NAME="8160"></A>
<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./EMISC_FR.HTM" TARGET="_top">Miscellany</A> &nbsp;&nbsp;<BR>&nbsp;&nbsp;Continue to <A HREF="./EI46_FR.HTM" TARGET="_top">Item 46: Prefer compile-time and link-time errors to runtime errors.</A></FONT></DIV>


<P><A NAME="dingp1"></A><FONT ID="eititle">Item 45: &nbsp;Know what functions C++ silently writes and calls.</FONT><SCRIPT>create_link(1);</SCRIPT>

</P>

<A NAME="8163"></A>
<P><A NAME="dingp2"></A>
When is an empty class not an empty class? When C++ gets through with it. If you don't declare them yourself, your thoughtful compilers will declare their own versions of a copy constructor, an assignment operator, a destructor, and a pair of address-of operators. Furthermore, if you don't declare any constructors, they will declare a default constructor for you, too. All these functions will be public. In other words, if you write <NOBR>this,<SCRIPT>create_link(2);</SCRIPT>

</NOBR></P>
<A NAME="8166"></A>
<UL><PRE>class Empty{};
</PRE>
</UL><A NAME="8167"></A><p><A NAME="dingp3"></A>it's the same as if you'd written <NOBR>this:<SCRIPT>create_link(3);</SCRIPT>

</NOBR></P>
<A NAME="8169"></A>
<UL><PRE>class Empty {
public:
  Empty();                        // default constructor
  Empty(const Empty&amp; rhs);        // copy constructor
</PRE>
</UL><A NAME="23223"></A>
<UL><PRE>
  ~Empty();                       // destructor &#151; see
                                  // below for whether
                                  // it's virtual
  Empty&amp;
  operator=(const Empty&amp; rhs);    // assignment operator
</PRE>
</UL><A NAME="8171"></A>
<UL><PRE>
  Empty* operator&amp;();             // address-of operators
  const Empty* operator&amp;() const;
};
</PRE>
</UL></P><A NAME="8174"></A>
<P><A NAME="dingp4"></A>
<A NAME="p213"></A>Now these functions are generated only if they are needed, but it doesn't take much to need them. The following code will cause each function to be <NOBR>generated:<SCRIPT>create_link(4);</SCRIPT>

</NOBR></P>
<A NAME="8175"></A>
<UL><PRE>
const Empty e1;                     // default constructor;
                                    // destructor
</PRE>
</UL><A NAME="23271"></A>
<UL><PRE>
Empty e2(e1);                       // copy constructor
</PRE>
</UL><A NAME="23272"></A>
<UL><PRE>
e2 = e1;                            // assignment operator
</PRE>
</UL><A NAME="8176"></A>
<UL><PRE>
Empty *pe2 = &amp;e2;                   // address-of
                                    // operator (non-const)
</PRE>
</UL><A NAME="8177"></A>
<UL><PRE>
const Empty *pe1 = &amp;e1;             // address-of
                                    // operator (const)
</PRE>
</UL><A NAME="222409"></A>
<P><A NAME="dingp5"></A>
Given that compilers are writing functions for you, what do the functions do? Well, the default constructor and the destructor don't really do anything. They just enable you to create and destroy objects of the class. (They also provide a convenient place for implementers to place code whose execution takes care of "behind the scenes" behavior &#151; see Items <A HREF="./EI33_FR.HTM#6729" TARGET="_top">33</A> and <A HREF="../MEC/MI24_FR.HTM#41284" TARGET="_top">M24</A>.) Note that the generated destructor is nonvirtual (see <A HREF="./EI14_FR.HTM#223029" TARGET="_top">Item 14</A>) unless it's for a class inheriting from a base class that itself declares a virtual destructor. The default address-of operators just return the address of the object. These functions are effectively defined like <NOBR>this:<SCRIPT>create_link(5);</SCRIPT>

</NOBR></P>
<A NAME="8180"></A>
<UL><PRE>inline Empty::Empty() {}
</PRE>
</UL><A NAME="23286"></A>
<UL><PRE>inline Empty::~Empty() {}
</PRE>
</UL><A NAME="8182"></A>
<UL><PRE>inline Empty * Empty::operator&amp;() { return this; }
</PRE>
</UL><A NAME="8184"></A>
<UL><PRE>inline const Empty * Empty::operator&amp;() const
{ return this; }
</PRE>
</UL><A NAME="8187"></A>
<P><A NAME="dingp6"></A>
As for the copy constructor and the assignment operator, the official rule is this: the default copy constructor (assignment operator) performs memberwise copy construction (assignment) of the nonstatic data members of the class. That is, if <CODE>m</CODE> is a nonstatic data member of type <CODE>T</CODE> in a class <CODE>C</CODE> and <CODE>C</CODE> declares no copy constructor (assignment operator), <CODE>m</CODE> will be copy constructed (assigned) using the copy constructor (assignment operator) defined for <CODE>T</CODE>, if there is one. If there isn't, this rule will be recursively applied to <CODE>m</CODE>'s data members until a copy constructor (assignment operator) or built-in type (e.g., <CODE>int</CODE>, <CODE>double</CODE>, pointer, etc.) is found. By default, objects of built-in types are copy constructed (assigned) using bitwise copy from the source object to the destination object. For classes that inherit from other classes, this rule is applied to each level of the inheritance hierarchy, so user-defined copy constructors and assignment operators are called at whatever level they are <NOBR>declared.<SCRIPT>create_link(6);</SCRIPT>

</NOBR></P>
<A NAME="8191"></A>
<P><A NAME="dingp7"></A>
I hope that's crystal <NOBR>clear.<SCRIPT>create_link(7);</SCRIPT>

</NOBR></P>
<A NAME="23653"></A>
<P><A NAME="dingp8"></A>
<A NAME="p214"></A>But just in case it's not, here's an example. Consider the definition of a <CODE>NamedObject</CODE> template, whose instances are classes allowing you to associate names with <NOBR>objects:<SCRIPT>create_link(8);</SCRIPT>

</NOBR></P>
<A NAME="8197"></A>
<UL><PRE>template&lt;class T&gt;
class NamedObject {
public:
  NamedObject(const char *name, const T&amp; value);
  NamedObject(const string&amp; name, const T&amp; value);
</PRE>
</UL><A NAME="8199"></A>
<UL><PRE>  ...
</PRE>
</UL><A NAME="23315"></A>
<UL><PRE>private:
  string nameValue;
  T objectValue;
};
</PRE>
</UL><A NAME="8201"></A>
<P><A NAME="dingp9"></A>
Because the <CODE>NamedObject</CODE> classes declare at least one constructor, compilers won't generate default constructors, but because the classes fail to declare copy constructors or assignment operators, compilers will generate those functions (if they are <NOBR>needed).<SCRIPT>create_link(9);</SCRIPT>

</NOBR></P>
<A NAME="24864"></A>
<P><A NAME="dingp10"></A>
Consider the following call to a copy constructor:<SCRIPT>create_link(10);</SCRIPT>

<A NAME="8202"></A>
<UL><PRE>NamedObject&lt;int&gt; no1("Smallest Prime Number", 2);
</PRE>
</UL><A NAME="8203"></A>
<UL><PRE>NamedObject&lt;int&gt; no2(no1);      // calls copy constructor
</PRE>
</UL></P><A NAME="8204"></A>
<P><A NAME="dingp11"></A>
The copy constructor generated by your compilers must initialize <CODE>no2.nameValue</CODE> and <CODE>no2.objectValue</CODE> using <CODE>no1.nameValue</CODE> and <CODE>no1.objectValue</CODE>, respectively. The type of <CODE>nameValue</CODE> is <CODE>string</CODE>, and <CODE>string</CODE> has a copy constructor (which you can verify by examining <CODE>string</CODE> in the standard library &#151; see <A HREF="./EI49_FR.HTM#8392" TARGET="_top">Item 49</A>), so <CODE>no2.nameValue</CODE> will be initialized by calling the <CODE>string</CODE> copy constructor with <CODE>no1.nameValue</CODE> as its argument. On the other hand, the type of <CODE>NamedObject&lt;int&gt;::objectValue</CODE> is <CODE>int</CODE> (because <CODE>T</CODE> is <CODE>int</CODE> for this template instantiation), and no copy constructor is defined for <CODE>int</CODE>s, so <CODE>no2.objectValue</CODE> will be initialized by copying the bits over from <CODE>no1.objectValue</CODE>.<SCRIPT>create_link(11);</SCRIPT>

</P>
<A NAME="24879"></A>
<P><A NAME="dingp12"></A>
The compiler-generated assignment operator for <CODE>NamedObject&lt;int&gt;</CODE> would behave the same way, but in general, compiler-generated assignment operators behave as I've described only when the resulting code is both legal and has a reasonable chance of making sense. If either of these tests fails, compilers will refuse to generate an <CODE>operator=</CODE> for your class, and you'll receive some lovely diagnostic during <NOBR>compilation.<SCRIPT>create_link(12);</SCRIPT>

</NOBR></P>
<A NAME="23730"></A>
<P><A NAME="dingp13"></A>
For example, suppose <CODE>NamedObject</CODE> were defined like this, where <CODE>nameValue</CODE> is a <I>reference</I> to a string and <CODE>objectValue</CODE> is a <CODE><I>const</I></CODE> <CODE>T</CODE>:<SCRIPT>create_link(13);</SCRIPT>

</P>
<A NAME="222842"></A>
<UL><PRE><A NAME="p215"></A>template&lt;class T&gt;
class NamedObject {
public:
  // this ctor no longer takes a const name, because name-
  // Value is now a reference-to-non-const string. The char*
  // ctor is gone, because we must have a string to refer to
  NamedObject(string&amp; name, const T&amp; value);
</PRE>
</UL><A NAME="222844"></A>
<UL><PRE>
  ...                          // as above, assume no
                               // operator= is declared
private:
  string&amp; nameValue;           // this is now a reference
  const T objectValue;         // this is now const
};
</PRE>
</UL></P><A NAME="222845"></A>
<P><A NAME="dingp14"></A>
Now consider what should happen <NOBR>here:<SCRIPT>create_link(14);</SCRIPT>

</NOBR></P>
<A NAME="222846"></A>
<UL><PRE>string newDog("Persephone");
string oldDog("Satch");
</PRE>
</UL><A NAME="222848"></A>
<UL><PRE>
NamedObject&lt;int&gt; p(newDog, 2);      // as I write this, our dog
                                    // <NOBR><FONT COLOR="#FF0000" SIZE="-2"><B>&deg;</B></FONT><A HREF="http://www.awl.com/cseng/cgi-bin/cdquery.pl?name=pers" onMouseOver = "self.status = 'Persephone`s Link'; return true" onMouseOut = "self.status = self.defaultStatus" TARGET="_top"></NOBR>Persephone</A> is about to
                                    // have her second birthday
</PRE>
</UL><A NAME="222849"></A>
<UL><PRE>
NamedObject&lt;int&gt; s(oldDog, 29);     // the family dog Satch
                                    // (from my childhood)
                                    // would be 29 if she were
                                    // still alive
</PRE>
</UL><A NAME="222850"></A>
<UL><PRE>
p = s;                              // what should happen to
                                    // the data members in p?
</PRE>
</UL><A NAME="23521"></A>
<P><A NAME="dingp15"></A>
Before the assignment, <CODE>p.nameValue</CODE> refers to some <CODE>string</CODE> object and <CODE>s.nameValue</CODE> also refers to a <CODE>string</CODE>, though not the same one. How should the assignment affect <CODE>p.nameValue</CODE>? After the assignment, should <CODE>p.nameValue</CODE> refer to the <CODE>string</CODE> referred to by <CODE>s.nameValue</CODE>, i.e., should the reference itself be modified? If so, that breaks new ground, because C++ doesn't provide a way to make a reference refer to a different object (see <A HREF="../MEC/MI1_FR.HTM#11029" TARGET="_top">Item M1</A>). Alternatively, should the <CODE>string</CODE> object to which <CODE>p.nameValue</CODE> refers be modified, thus affecting other objects that hold pointers or references to that <CODE>string</CODE>, i.e., objects not directly involved in the assignment? Is that what the compiler-generated assignment operator should <NOBR>do?<SCRIPT>create_link(15);</SCRIPT>

</NOBR></P>
<A NAME="23503"></A>
<P><A NAME="dingp16"></A>
Faced with such a conundrum, C++ refuses to compile the code. If you want to support assignment in a class containing a reference member, you must define the assignment operator yourself. Compilers behave similarly for classes containing <CODE>const</CODE> members (such as <CODE>objectValue</CODE> in the modified class above); it's not legal to modify <CODE>const</CODE> members, so compilers are unsure how to treat them during an implicitly generated assignment function. Finally, compilers refuse to generate assignment operators for derived classes that inherit from base classes declaring the standard assignment operator <CODE>private</CODE>. After all, compiler-gener<A NAME="p216"></A>ated assignment operators for derived classes are supposed to handle base class parts, too (see Items <A HREF="./EI16_FR.HTM#2225" TARGET="_top">16</A> and <A HREF="../MEC/MI33_FR.HTM#10947" TARGET="_top">M33</A>), but in doing so, they certainly shouldn't invoke member functions the derived class has no right to <NOBR>call.<SCRIPT>create_link(16);</SCRIPT>

</NOBR></P>
<A NAME="24870"></A>
<P><A NAME="dingp17"></A>
All this talk of compiler-generated functions gives rise to the question, what do you do if you want to disallow use of those functions? That is, what if you deliberately don't declare, for example, an <CODE>operator=</CODE> because you never <I>ever</I> want to allow assignment of objects in your class? The solution to that little teaser is the subject of <A HREF="./EI27_FR.HTM#6406" TARGET="_top">Item 27</A>. For a discussion of the often-overlooked interactions between pointer members and compiler-generated copy constructors and assignment operators, check out <A HREF="./EI11_FR.HTM#2042" TARGET="_top">Item 11</A>.<SCRIPT>create_link(17);</SCRIPT>

</P>

<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./EMISC_FR.HTM" TARGET="_top">Miscellany</A> &nbsp;&nbsp;<BR>&nbsp;&nbsp;Continue to <A HREF="./EI46_FR.HTM" TARGET="_top">Item 46: Prefer compile-time and link-time errors to runtime errors.</A></FONT></DIV>

</BODY>
</HTML>

⌨️ 快捷键说明

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