📄 chapter06.html
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<!--
This document was converted from RTF source:
By rtftohtml 4.19
See http://www.sunpack.com/RTF
Filename:TIC2Vone.rtf
Application Directory:C:\TOOLS\RTF2HTML\
Subject:
Author:Bruce Eckel
Operator:Bruce Eckel
Document Comments:
Version Comments:
Comments:
Keywords:
Translation Date:09/27/2001
Translation Time:05:25:33
Translation Platform:Win32
Number of Output files:22
This File:Chapter06.html
SplitDepth=1
SkipNavPanel=1
SkipLeadingToc=1
SkipTrailingToc=1
GenContents=1
GenFrames=1
GenIndex=1
-->
<HEAD lang="en"><META http-equiv="Content-Type" content="text/html">
<TITLE>6: Initialization & Cleanup</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF"><DIV ALIGN="CENTER">
<a href="http://www.MindView.net">
<img src="mindview-head.gif" alt="MindView Inc." BORDER = "0"></a>
<CENTER>
<FONT FACE="Verdana" size = "-1">
[ <a href="README-HTML.txt">Viewing Hints</a> ]
[ <a href="http://www.mindview.net/CPPServices/SolutionGuide.html">Exercise Solutions</a> ]
[ <a href="http://www.mindview.net/ThinkingInCPP2e.html">Volume 2</a> ]
[ <a href="http://www.mindview.net/MailingList.html">Free Newsletter</a> ] <br>
[ <a href="http://www.mindview.net/CPPServices/#PublicSeminars">Seminars</a> ]
[ <a href="http://www.mindview.net/CPPServices/#SeminarsOnCD">Seminars on CD ROM</a> ]
[ <a href="http://www.mindview.net/CPPServices/#ConsultingServices">Consulting</a> ]
</FONT>
<H2><FONT FACE="Verdana">
Thinking in C++, 2nd ed. Volume 1</FONT></H2></FONT>
<H3><FONT FACE="Verdana">©2000 by Bruce Eckel</FONT></H3></FONT>
<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>
</CENTER>
</P></DIV><A NAME="_Toc472654852"></A><A NAME="Heading224"></A><FONT FACE = "Verdana"><H1 ALIGN="LEFT">
6: Initialization & Cleanup</H1></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Verdana" SIZE=4>Chapter 4 made a significant
improvement in library </FONT><BR><FONT FACE="Verdana" SIZE=4>use by taking all
the scattered components of a typical </FONT><BR><FONT FACE="Verdana" SIZE=4>C
library and encapsulating them into a structure (an abstract data type, called a
<I>class</I> from now on). </FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This not only provides a single unified
point of entry into a library component, but it also hides the names of the
functions within the class name. In Chapter 5, access control (implementation
hiding) was introduced. This gives the class designer a way to establish clear
boundaries for determining what the client programmer is allowed to manipulate
and what is off limits. It means the internal mechanisms of a data type’s
operation are under the control and discretion of the class designer, and
it’s clear to client programmers what members they can and should pay
attention to.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Together, encapsulation and access
control make a significant step in improving the ease of library use. The
concept of “new data type” they provide is better in some ways than
the existing built-in data types from C. The C++ compiler can now provide
type-checking guarantees for that data type and thus ensure a level of safety
when that data type is being used.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">When it comes to safety, however,
there’s a lot more the compiler can do for us than C provides. In this and
future chapters, you’ll see additional features that have been engineered
into C++ that make the bugs in your program almost leap out and grab you,
sometimes before you even compile the program, but usually in the form of
compiler warnings and errors. For this reason, you will soon get used to the
unlikely-sounding scenario that a C++ program that compiles often runs right the
first time.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Two of these safety issues are
initialization and cleanup. A large segment of C bugs occur when the programmer
forgets to initialize or clean up a variable. This is especially true with C
libraries, when client programmers don’t know how to initialize a
<B>struct</B>, or even that they must. (Libraries often do not include an
initialization function, so the client programmer is forced to initialize the
<B>struct</B> by hand.) Cleanup is a special problem because C programmers are
comfortable with forgetting about variables once they are finished, so any
cleaning up that may be necessary for a library’s <B>struct</B> is often
missed.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In C++, the concept of initialization and
cleanup is essential for easy library use and to eliminate the many subtle bugs
that occur when the client programmer forgets to perform these activities. This
chapter examines the features in C++ that help guarantee proper initialization
and
cleanup.</FONT><A NAME="_Toc312373853"></A><A NAME="_Toc472654853"></A><BR></P></DIV>
<A NAME="Heading225"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Guaranteed initialization with the constructor</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Both the <B>Stash</B> and <B>Stack</B>
classes defined previously have a function called <B>initialize( )</B>,
which hints by its name that it should be called before using the object in any
other way. Unfortunately, this means the client programmer must ensure proper
initialization. Client programmers are prone to miss details like initialization
in their headlong rush to make your amazing library solve their problem. In C++,
initialization is too important to leave to the client programmer. The class
designer can guarantee initialization of every object by providing a special
function called the
<I>constructor<A NAME="Index1288"></A><A NAME="Index1289"></A></I>. If a class
has a constructor, the compiler automatically calls that constructor at the
point an object is created, before client programmers can get their hands on the
object. The constructor call isn’t even an option for the client
programmer; it is performed by the compiler at the point the object
<A NAME="Index1290"></A><A NAME="Index1291"></A>is defined.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The next challenge is what to name this
function. There are two issues. The first is that any name you use is something
that can potentially clash with a name you might like to use as a member in the
class. The second is that because the compiler is responsible for calling the
constructor, it must always know which function to call. The solution Stroustrup
chose seems the easiest and most logical: the <A NAME="Index1292"></A>name of
the constructor <A NAME="Index1293"></A>is the same as the name of the class. It
makes sense that such a function will be called automatically on
initialization.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here’s a simple class with a
constructor:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>class</font> X {
<font color=#0000ff>int</font> i;
<font color=#0000ff>public</font>:
X(); <font color=#009900>// Constructor</font>
}; </PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Now, when an object is
defined,</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>void</font> f() {
X a;
<font color=#009900>// ...</font>
} </PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">the same thing happens as if <B>a</B>
were an <B>int</B>: storage is allocated for the object. But when the program
reaches the <I>sequence point</I>
<A NAME="Index1294"></A><A NAME="Index1295"></A>(point of execution) where
<B>a</B> is defined, the constructor is called automatically. That is, the
compiler quietly inserts the call to <B>X::X( )</B> for the object <B>a</B>
at the point of definition. Like any member function, the first (secret)
argument to the constructor is the
<A NAME="Index1296"></A><A NAME="Index1297"></A><B>this </B>pointer – the
address of the object for which it is being called. In the case of the
constructor, however, <B>this</B> is pointing to an un-initialized block of
memory, and it’s the job of the constructor to initialize this memory
properly.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Like any function, the constructor can
have arguments<A NAME="Index1298"></A><A NAME="Index1299"></A> to allow you to
specify how an object is created, give it initialization values, and so on.
Constructor arguments provide you with a way to guarantee that all parts of your
object are initialized to appropriate values. For example, if a class
<B>Tree</B> has a constructor that takes a single integer argument denoting the
height of the tree, then you must create a tree object like
this:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>Tree t(12); <font color=#009900>// 12-foot tree</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">If <B>Tree(int)</B> is your only
constructor, the compiler won’t let you create an object any other way.
(We’ll look at multiple constructors and different ways to call
constructors in the next chapter.)</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">That’s really all there is to a
constructor; it’s a specially named function that is called automatically
by the compiler for every object at the point of that object’s creation.
Despite it’s simplicity, it is exceptionally valuable because it
eliminates a large class of problems and makes the code easier to write and
read. In the preceding code fragment, for example, you don’t see an
explicit function call to some <B>initialize( )</B> function that is
conceptually separate from definition. In C++, definition and initialization are
unified concepts – you can’t have one without the
other.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Both the constructor and destructor are
very unusual types of functions: they have no return
value<A NAME="Index1300"></A><A NAME="Index1301"></A>. This is distinctly
different from a <B>void</B> return value, in which the function returns nothing
but you still have the option to make it something else. Constructors and
destructors return nothing and you don’t have an option. The acts of
bringing an object into and out of the program are special, like birth and
death, and the compiler always makes the function calls itself, to make sure
they happen. If there were a return value, and if you could select your own, the
compiler would somehow have to know what to do with the return value, or the
client programmer would have to explicitly call constructors and destructors,
which would eliminate their
safety.</FONT><A NAME="_Toc312373854"></A><A NAME="_Toc472654854"></A><BR></P></DIV>
<A NAME="Heading226"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Guaranteed cleanup with the destructor</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">As a C programmer, you often think about
the importance of initialization, but it’s rarer to think about cleanup.
After all, what do you need to do to clean up an <B>int</B>? Just forget about
it. However, with libraries, just “letting go” of an object once
you’re done with it is not so safe. What if it modifies some piece of
hardware, or puts something on the screen, or allocates storage on the heap? If
you just forget about it, your object never achieves closure upon its exit from
this world. In C++, cleanup is as important as initialization and is therefore
guaranteed with the
<A NAME="Index1302"></A>destructor<A NAME="Index1303"></A>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The syntax for the destructor is similar
to that for the constructor: the class name is used for the name of the
function. However, the destructor is distinguished from the constructor by a
leading tilde (<B>~</B>). In addition, the destructor never has any arguments
<A NAME="Index1304"></A>because destruction never needs any options.
Here’s the declaration for a destructor:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>class</font> Y {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -