📄 chapter06.html
字号:
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>Y y1[] = { Y(1), Y(2), Y(3) };</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You get three objects and three
constructor calls. Any<I> </I>time you have a constructor, whether it’s a
<B>struct</B> with all members <B>public</B> or a <B>class</B> with
<B>private</B> data members, all the initialization must go through the
constructor, even if you’re using aggregate
initialization.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here’s a second example showing
multiple constructor arguments:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C06:Multiarg.cpp</font>
<font color=#009900>// Multiple constructor arguments</font>
<font color=#009900>// with aggregate initialization</font>
#include <iostream>
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
<font color=#0000ff>class</font> Z {
<font color=#0000ff>int</font> i, j;
<font color=#0000ff>public</font>:
Z(<font color=#0000ff>int</font> ii, <font color=#0000ff>int</font> jj);
<font color=#0000ff>void</font> print();
};
Z::Z(<font color=#0000ff>int</font> ii, <font color=#0000ff>int</font> jj) {
i = ii;
j = jj;
}
<font color=#0000ff>void</font> Z::print() {
cout << <font color=#004488>"i = "</font> << i << <font color=#004488>", j = "</font> << j << endl;
}
<font color=#0000ff>int</font> main() {
Z zz[] = { Z(1,2), Z(3,4), Z(5,6), Z(7,8) };
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i < <font color=#0000ff>sizeof</font> zz / <font color=#0000ff>sizeof</font> *zz; i++)
zz[i].print();
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Notice that it looks like an explicit
constructor is called for each object in the
array.</FONT><A NAME="_Toc312373861"></A><A NAME="_Toc472654861"></A><BR></P></DIV>
<A NAME="Heading233"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Default constructors</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">A <I>default constructor</I>
<A NAME="Index1370"></A><A NAME="Index1371"></A>is one that can be called with
no arguments. A default constructor is used to create a “vanilla
object,” but it’s also important when the compiler is told to create
an object but isn’t given any details. For example, if you take the
<B>struct Y</B> defined previously and use it in a definition like
this,</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>Y y2[2] = { Y(1) };</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">the compiler will complain that it cannot
find a default constructor. The second object in the array wants to be created
with no arguments, and that’s where the compiler looks for a default
constructor. In fact, if you simply define an array of <B>Y</B>
objects,</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>Y y3[7];</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">the compiler will complain because it
must have a default constructor to initialize every object in the array.
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The same problem occurs if you create an
individual object like this:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>Y y4;</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Remember, if you have a constructor, the
compiler ensures that construction <I>always </I>happens, regardless of the
situation.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The default constructor is so important
that <I>if</I> (and only if) there are no <A NAME="Index1372"></A>constructors
for a structure (<B>struct</B> or <B>class</B>), the
<A NAME="Index1373"></A>compiler will automatically create one for you. So this
works:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C06:AutoDefaultConstructor.cpp</font>
<font color=#009900>// Automatically-generated default constructor</font>
<font color=#0000ff>class</font> V {
<font color=#0000ff>int</font> i; <font color=#009900>// private</font>
}; <font color=#009900>// No constructor</font>
<font color=#0000ff>int</font> main() {
V v, v2[10];
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">If any constructors are defined, however,
and there’s no default constructor, the instances of <B>V</B> above will
generate compile-time errors.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You might think that the
compiler-synthesized <A NAME="Index1374"></A>constructor should do some
intelligent initialization, like setting all the memory for the object to zero.
But it doesn’t – that would add extra overhead but be out of the
programmer’s control. If you want the memory to be initialized to zero,
you must do it yourself by writing the default constructor
explicitly.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Although the compiler will create a
default constructor for you, the behavior of the compiler-synthesized
constructor is rarely what you want. You should treat this feature as a safety
net, but use it sparingly. In general, you should define your constructors
explicitly and not allow the compiler to do it for
you.<A NAME="Index1375"></A><A NAME="Index1376"></A><A NAME="Index1377"></A><A NAME="_Toc312373862"></A></FONT><A NAME="_Toc472654862"></A><BR></P></DIV>
<A NAME="Heading234"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Summary</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The seemingly elaborate mechanisms
provided by C++ should give you a strong hint about the critical importance
placed on initialization and cleanup in the language. As Stroustrup was
designing C++, one of the first observations he made about productivity in C was
that a significant portion of programming problems are caused by improper
initialization of variables. These kinds of bugs are hard to find, and similar
issues apply to improper cleanup. Because constructors and destructors allow you
to <I>guarantee</I> proper initialization and cleanup (the compiler will not
allow an object to be created and destroyed without the proper constructor and
destructor calls), you get complete control and safety.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Aggregate initialization is included in a
similar vein – it prevents you from making typical initialization mistakes
with aggregates of built-in types and makes your code more
succinct.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Safety during coding is a big issue in
C++. Initialization and cleanup are an important part of this, but you’ll
also see other safety issues as the book
progresses.</FONT><A NAME="_Toc312373863"></A><A NAME="_Toc472654863"></A><BR></P></DIV>
<A NAME="Heading235"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Exercises</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia" SIZE=2>Solutions to selected exercises
can be found in the electronic document <I>The Thinking in C++ Annotated
Solution Guide</I>, available for a small fee from
www.BruceEckel.com.</FONT><BR></P></DIV>
<OL>
<LI><FONT FACE="Verdana"> </FONT><FONT FACE="Georgia">Write a simple class
called <B>Simple </B>with a constructor that prints something to tell you that
it’s been called. In <B>main( )</B> make an object of your
class.</FONT><LI><FONT FACE="Verdana"> </FONT><FONT FACE="Georgia">Add a
destructor to Exercise 1 that prints out a message to tell you that it’s
been called.</FONT><LI><FONT FACE="Verdana"> </FONT><FONT FACE="Georgia">Modify
Exercise 2 so that the class contains an <B>int</B> member. Modify the
constructor so that it takes an <B>int</B> argument that it stores in the class
member. Both the constructor and destructor should print out the <B>int</B>
value as part of their message, so you can see the objects as they are created
and
destroyed.</FONT><LI><FONT FACE="Verdana"> </FONT><FONT FACE="Georgia">Demonstrate
that destructors are still called even when <B>goto</B> is used to jump out of a
loop.</FONT><LI><FONT FACE="Verdana"> </FONT><FONT FACE="Georgia">Write two
<B>for</B> loops that print out values from zero to 10. In the first, define the
loop counter before the <B>for</B> loop, and in the second, define the loop
counter in the control expression of the <B>for</B> loop. For the second part of
this exercise, modify the identifier in the second <B>for</B> loop so that it as
the same name as the loop counter for the first and see what your compiler
does.</FONT><LI><FONT FACE="Verdana"> </FONT><FONT FACE="Georgia">Modify the
<B>Handle.h</B>, <B>Handle.cpp</B>, and <B>UseHandle.cpp </B>files at the end of
Chapter 5 to use constructors and
destructors.</FONT><LI><FONT FACE="Verdana"> </FONT><FONT FACE="Georgia">Use
aggregate initialization to create an array of <B>double</B> in which you
specify the size of the array but do not provide enough elements. Print out this
array using <B>sizeof </B>to determine the size of the array. Now create an
array of <B>double</B> using aggregate initialization <I>and</I> automatic
counting. Print out the
array.</FONT><LI><FONT FACE="Verdana"> </FONT><FONT FACE="Georgia">Use aggregate
initialization to create an array of <B>string</B> objects. Create a
<B>Stack</B> to hold these <B>string</B>s and step through your array, pushing
each <B>string</B> on your <B>Stack</B>. Finally, <B>pop</B> the <B>string</B>s
off your <B>Stack</B> and print each
one.</FONT><LI><FONT FACE="Verdana"> </FONT><FONT FACE="Georgia">Demonstrate
automatic counting and aggregate initialization with an array of objects of the
class you created in Exercise 3. Add a member function to that class that prints
a message. Calculate the size of the array and move through it, calling your new
member
function.</FONT><LI><FONT FACE="Verdana"> </FONT><FONT FACE="Georgia">Create a
class without any constructors, and show that you can create objects with the
default constructor. Now create a nondefault constructor (one with an argument)
for the class, and try compiling again. Explain what
happened.</FONT><A NAME="_Toc465909232"></A><A NAME="_Toc465909645"></A><A NAME="_Toc466014556"></A><A NAME="_Toc466073466"></A><A NAME="_Toc466083267"></A><A NAME="_Toc468608073"></A><A NAME="_Toc468771394"></A><A NAME="_Toc312373864"></A><A NAME="_Toc469811397"></A><A NAME="_Toc469821282"></A><A NAME="_Toc469821698"></A><A NAME="_Toc469825379"></A><A NAME="_Toc469874284"></A><A NAME="_Toc470615940"></A><A NAME="_Toc470655078"></A><A NAME="_Toc470821062"></A><A NAME="_Toc470821479"></A><A NAME="_Toc470911576"></A><A NAME="_Toc471359057"></A><A NAME="_Toc471489477"></A><A NAME="_Toc471528908"></A><A NAME="_Toc471795064"></A><A NAME="_Toc471965641"></A><A NAME="_Toc472045643"></A><A NAME="_Toc472255847"></A><A NAME="_Toc472654450"></A><A NAME="_Toc472654864"></A></OL><FONT FACE = "Verdana"><H1 ALIGN="LEFT">
</H1></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Verdana"><B></B></FONT><BR></P></DIV>
<FONT FACE = "Verdana"><H1 ALIGN="LEFT">
</H1></FONT>
<HR><DIV ALIGN="LEFT"><P><A NAME="fn38" HREF="#fnB38">[38]</A><FONT FACE="Georgia" SIZE=2>
C99, The updated version of Standard C, allows variables to be defined at any
point in a scope, like C++.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><A NAME="fn39" HREF="#fnB39">[39]</A><FONT FACE="Georgia" SIZE=2>
An earlier iteration of the C++ draft standard said the variable lifetime
extended to the end of the scope that enclosed the <B>for</B> loop. Some
compilers still implement that, but it is not correct so your code will only be
portable if you limit the scope to the <B>for</B> loop.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><A NAME="fn40" HREF="#fnB40">[40]</A><FONT FACE="Georgia" SIZE=2>
The Java language considers this such a bad idea that it flags such code as an
error.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><A NAME="fn41" HREF="#fnB41">[41]</A><FONT FACE="Georgia" SIZE=2>
OK, you probably could by fooling around with pointers, but you’d be very,
very bad.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><A NAME="fn42" HREF="#fnB42">[42]</A><FONT FACE="Georgia" SIZE=2>
In Volume 2 of this book (freely available at www.BruceEckel.com), you’ll
see a more succinct calculation of an array size using
templates.</FONT><BR></P></DIV>
<DIV ALIGN="CENTER">
<FONT FACE="Verdana" size = "-1">
[ <a href="Chapter05.html">Previous Chapter</a> ]
[ <a href="Contents.html">Table of Contents</a> ]
[ <a href="DocIndex.html">Index</a> ]
[ <a href="Chapter07.html">Next Chapter</a> ]
</FONT>
<BR>
Last Update:09/27/2001</P></DIV>
</BODY>
</HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -