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

📄 wwwtc5answer.htm

📁 C++builder学习资料C++builder
💻 HTM
字号:


<HTML>

<HEAD>

   <TITLE> Answer What's Wrong With This Code? Volume #5</TITLE>

   <META NAME="Author" CONTENT="Harold Howe">

</HEAD>

<BODY>



<CENTER>

<TABLE  BORDER=0 CELLPADDING=0 CELLSPACING=0 WIDTH="640">

<TR>



<TD>







<H2>

Answer What's Wrong With This Code? Volume #5 

</H2> 

 

<H4> 

Copy constructors <BR> 

<I> by Chris Uzdavinis</I> 

</H4> 

<P> 

For reference, here is a copy of the code. 

</P> 

<pre>

<font color="green">#include &lt;iostream&gt;</font>

<b>using</b> std<b>:</b><b>:</b>cout<b>;</b>

<b>using</b> std<b>:</b><b>:</b>endl<b>;</b>



<b>class</b> Base

<b>{</b>

<b>public</b><b>:</b>

  Base<b>(</b><b>)</b>                                    <b>{</b> cout <b>&lt;&lt;</b> <font color="blue">&quot;1&quot;</font> <b>&lt;&lt;</b> endl<b>;</b><b>}</b>

  Base<b>(</b>Base <b>const</b> <b>&amp;</b> rhs<b>)</b>                    <b>{</b> cout <b>&lt;&lt;</b> <font color="blue">&quot;2&quot;</font> <b>&lt;&lt;</b> endl<b>;</b><b>}</b>

  <b>virtual</b> <b>~</b>Base<b>(</b><b>)</b>                           <b>{</b> cout <b>&lt;&lt;</b> <font color="blue">&quot;3&quot;</font> <b>&lt;&lt;</b> endl<b>;</b><b>}</b>

<b>}</b><b>;</b>





<b>class</b> Derived <b>:</b> <b>public</b> Base

<b>{</b>

<b>public</b><b>:</b>

  Derived<b>(</b><b>)</b> <b>:</b> x_<b>(</b><font color="blue">0</font><b>)</b>                         <b>{</b> cout <b>&lt;&lt;</b> <font color="blue">&quot;4&quot;</font> <b>&lt;&lt;</b> endl<b>;</b><b>}</b>

  Derived<b>(</b><b>int</b> x<b>)</b> <b>:</b> x_<b>(</b>x<b>)</b>                    <b>{</b> cout <b>&lt;&lt;</b> <font color="blue">&quot;5&quot;</font> <b>&lt;&lt;</b> endl<b>;</b><b>}</b>

  Derived<b>(</b>Derived <b>const</b> <b>&amp;</b> rhs<b>)</b> <b>:</b> x_<b>(</b>rhs<b>.</b>x_<b>)</b> <b>{</b> cout <b>&lt;&lt;</b> <font color="blue">&quot;6&quot;</font> <b>&lt;&lt;</b> endl<b>;</b><b>}</b>

  <b>~</b>Derived<b>(</b><b>)</b> <b>{</b> <b>}</b>



  <b>int</b> get_x<b>(</b><b>)</b> <b>const</b> <b>{</b> <b>return</b> x_<b>;</b> <b>}</b>

<b>private</b><b>:</b>

  <b>int</b> x_<b>;</b>

<b>}</b><b>;</b>





main<b>(</b><b>)</b>

<b>{</b>

  Derived d1<b>(</b><font color="blue">999</font><b>)</b><b>;</b>

  <font color="navy">// copy construct d2 from d1</font>

  Derived d2<b>(</b>d1<b>)</b><b>;</b>

<b>}</b>

</pre> 

<P> 

The output of the program is : 

</P> 

<PRE>

1

5

1

6

3

3

</PRE> 

<P> 

The first two lines of output correspond to the construction of <TT>d1</TT>. Everything 

is fine here. The next two lines correspond to the copy construction of <TT>d2</TT>. The 

last two lines come from the <TT>Base</TT> destructor. 

</P> 

<P> 

What is surprising is that <TT>Base</TT>'s copy constructor is never called. We would 

see a 2 in the output somewhere if it was.  When <TT>d2</TT> is created, it calls 

<TT>Base</TT>'s *default* constructor, then <TT>Derived</TT>'s copy constructor. 

Why isn't the <TT>Base</TT> copy constructor called? 

</P> 

<P> 

Since the programmer supplied the copy constructor for <TT>Derived</TT>, the 

compiler gives full responsibility to the programmer to implement it 

completely.  This responsibility means that the derived copy 

constructor is obligated to EXPLICITLY call the base class copy constructor. 

If the derived class does not fulfill this obligation, then the 

compiler will default construct the base part of the newly created 

object.  It is, afterall, what is supposed to get called by default. 

</P> 

<P> 

So why is this a big deal? When we create a copy of <TT>d1</TT>, we want a complete 

copy of it. <TT>d2</TT> should be an identical clone of <TT>d1</TT>. This includes both the base part of 

<TT>d1</TT>, and the derived part. Our code has a bug in its cloning routine. The derived part of <TT>d1</TT> 

is copied correctly, but the base part is not. <TT>d2</tt> ends up being a partial clone of <TT>d1</TT>. 

<P> 

This is a major bug that is very common.  Copy construction that 

doesn't explicitly call the base class copy constructor usually has 

unexpected results, and may contribute to more bugs than most people 

realize.  In most cases, one would expect that the copy 

constructor actually copy the values from the right-hand parameter. 

But when the copy constructor of the derived class is coded incorrectly, only the derived parts of the 

right hand parameter get copied. When this happens, it can be very difficult to detect. 

</P> 

<P> 

If you have written any derived objects that have copy constructors, 

it is worth a minute of your time to look at each of them to ensure 

that the base copy constructor is explicitly called.  Here is a 

corrected version of <TT>Derived</TT>. Only the copy constructror has changed. 

</P> 

<pre>

<b>class</b> Derived <b>:</b> <b>public</b> Base

<b>{</b>

<b>public</b><b>:</b>

  Derived<b>(</b><b>)</b> <b>:</b> x_<b>(</b><font color="blue">0</font><b>)</b>                         <b>{</b> cout <b>&lt;&lt;</b> <font color="blue">&quot;4&quot;</font> <b>&lt;&lt;</b> endl<b>;</b><b>}</b>

  Derived<b>(</b><b>int</b> x<b>)</b> <b>:</b> x_<b>(</b>x<b>)</b>                    <b>{</b> cout <b>&lt;&lt;</b> <font color="blue">&quot;5&quot;</font> <b>&lt;&lt;</b> endl<b>;</b><b>}</b>



  <font color="navy">// explicitly call base's copy ctor</font>

  Derived<b>(</b>Derived <b>const</b> <b>&amp;</b> rhs<b>)</b>

    <b>:</b> Base<b>(</b>rhs<b>)</b>

    <b>,</b> x_<b>(</b>rhs<b>.</b>x_<b>)</b>                            <b>{</b> cout <b>&lt;&lt;</b> <font color="blue">&quot;6&quot;</font> <b>&lt;&lt;</b> endl<b>;</b><b>}</b>



  <b>~</b>Derived<b>(</b><b>)</b> <b>{</b> <b>}</b>



  <b>int</b> get_x<b>(</b><b>)</b> <b>const</b> <b>{</b> <b>return</b> x_<b>;</b> <b>}</b>

<b>private</b><b>:</b>

  <b>int</b> x_<b>;</b>

<b>}</b><b>;</b>

</pre> 

<P> 

After fixing the copy constructor, the output becomes 

</P> 

<PRE>

1

5

2

6

3

3

</PRE> 

<P> 

Which is what we most likely expect. Lines 3 and 4 correspond to the copy construction of <TT>d2</TT>. 

Notice that the default constructor for the base class is gone (#1). It has been replaced with the copy 

constructor for the base class (#2). Remember, the order of 

initialization for a derived object is first to call the constructor 

of its base class(s), in order of declaration from left to right. 

Then call the member constructors (initializer list), then execute the 

body of this constructor.)  Destructors are called in the opposite order. 

</P> 

 

 

</TD> </TR> 

 

</TABLE> 

</CENTER> 

</BODY> 

</HTML> 

⌨️ 快捷键说明

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