📄 chapter10.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:41
Translation Platform:Win32
Number of Output files:22
This File:Chapter10.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>10: Name Control</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="Chapter09.html">Previous Chapter</a> ]
[ <a href="Contents.html">Table of Contents</a> ]
[ <a href="DocIndex.html">Index</a> ]
[ <a href="Chapter11.html">Next Chapter</a> ]
</FONT>
</CENTER>
</P></DIV><A NAME="_Toc472654914"></A><A NAME="Heading295"></A><FONT FACE = "Verdana"><H1 ALIGN="LEFT">
10: Name Control</H1></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Verdana" SIZE=4>Creating names is a fundamental
activity in programming, and when a project gets large, the number of names can
easily be overwhelming.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">C++ allows you a great deal of control
over the creation and visibility of names, where storage for those names is
placed, and linkage for names.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <A NAME="Index1688"></A><B>static</B>
<A NAME="Index1689"></A>keyword was overloaded in C before people knew what the
term “overload” meant, and C++ has added yet another meaning. The
underlying concept with all uses of <B>static</B> seems to be “something
that holds its position” (like static electricity), whether that means a
physical location in memory or visibility within a file.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In this chapter, you’ll learn how
<B>static</B> controls storage and visibility, and an improved way to control
access to names via C++’s <I>namespace</I> feature. You’ll also find
out how to use functions that were written and compiled in
C.</FONT><A NAME="_Toc305593219"></A><A NAME="_Toc305628691"></A><A NAME="_Toc312373941"></A><A NAME="_Toc472654915"></A><BR></P></DIV>
<A NAME="Heading296"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Static elements from C</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In both C and C++ the keyword
<B>static</B> has two basic meanings, which unfortunately often step on each
other’s
toes<A NAME="Index1690"></A><A NAME="Index1691"></A><A NAME="Index1692"></A><A NAME="Index1693"></A><A NAME="Index1694"></A><A NAME="Index1695"></A>:</FONT><BR></P></DIV>
<OL>
<LI><FONT FACE="Verdana"> </FONT><FONT FACE="Georgia">Allocated once at a fixed
address; that is, the object is created in a special <I>static data area</I>
rather than on the stack each time a function is called. This is the concept of
<I>static storage</I>.
</FONT><LI><FONT FACE="Verdana"> </FONT><FONT FACE="Georgia">Local to a
particular translation unit (and local to a class scope in C++, as you will see
later). Here, <B>static</B> controls the <I>visibility</I> of a name, so that
name cannot be seen outside the translation unit or class. This also describes
the concept of <I>linkage</I>, which determines what names the linker will
see.</FONT></OL><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This section will look at
the above meanings of <B>static</B> as they were inherited from
C.</FONT><A NAME="_Toc312373942"></A><A NAME="_Toc472654916"></A><BR></P></DIV>
<A NAME="Heading297"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
static variables inside
functions<BR><A NAME="Index1696"></A><A NAME="Index1697"></A></H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">When you create a local variable inside a
function, the compiler allocates storage for that variable each time the
function is called by moving the stack pointer<A NAME="Index1698"></A> down an
appropriate amount. If there is an initializer for the variable, the
initialization is performed each time that sequence point is
passed.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Sometimes, however, you want to retain a
value between function calls. You could accomplish this by making a global
variable, but then that variable would not be under the sole control of the
function. C and C++ allow you to create a <B>static</B> object inside a
function; the storage for this object is not on the stack but instead in the
program’s static data area. This object is initialized only once, the
first time the function is called, and then retains its value between function
invocations. For example, the following function returns the next character in
the array each time the function is called:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C10:StaticVariablesInfunctions.cpp</font>
#include <font color=#004488>"../require.h"</font>
#include <iostream>
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
<font color=#0000ff>char</font> oneChar(<font color=#0000ff>const</font> <font color=#0000ff>char</font>* charArray = 0) {
<font color=#0000ff>static</font> <font color=#0000ff>const</font> <font color=#0000ff>char</font>* s;
<font color=#0000ff>if</font>(charArray) {
s = charArray;
<font color=#0000ff>return</font> *s;
}
<font color=#0000ff>else</font>
require(s, <font color=#004488>"un-initialized s"</font>);
<font color=#0000ff>if</font>(*s == '\0')
<font color=#0000ff>return</font> 0;
<font color=#0000ff>return</font> *s++;
}
<font color=#0000ff>char</font>* a = <font color=#004488>"abcdefghijklmnopqrstuvwxyz"</font>;
<font color=#0000ff>int</font> main() {
<font color=#009900>// oneChar(); // require() fails</font>
oneChar(a); <font color=#009900>// Initializes s to a</font>
<font color=#0000ff>char</font> c;
<font color=#0000ff>while</font>((c = oneChar()) != 0)
cout << c << endl;
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <B>static char* s</B> holds its value
between calls of <B>oneChar( )</B> because its storage is not part of the
stack frame of the function, but is in the static storage area of the program.
When you call <B>oneChar( )</B> with a <B>char*</B> argument, <B>s</B> is
assigned to that argument, and the first character of the array is returned.
Each subsequent call to <B>oneChar( )</B> <I>without</I> an argument
produces the default value of zero for <B>charArray</B>, which indicates to the
function that you are still extracting characters from the previously
initialized value of <B>s</B>. The function will continue to produce characters
until it reaches the null terminator of the character array, at which point it
stops incrementing the pointer so it doesn’t overrun the end of the
array.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">But what happens if you call
<B>oneChar( )</B> with no arguments and without previously initializing the
value of <B>s</B>? In the definition for <B>s</B>, you could have provided an
initializer,</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>static</font> <font color=#0000ff>char</font>* s = 0;</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">but if you do not provide an initializer
for a static variable of a built-in
type<A NAME="Index1699"></A><A NAME="Index1700"></A><A NAME="Index1701"></A><A NAME="Index1702"></A>,
the compiler guarantees that variable will be initialized to zero (converted to
the proper type) at program start-up. So in <B>oneChar( )</B>, the first
time the function is called, <B>s</B> is zero. In this case, the <B>if(!s)</B>
conditional will catch it.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The initialization above for <B>s</B> is
very simple, but initialization for static objects (like all other objects) can
be arbitrary expressions involving constants and previously declared variables
and functions.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You should be aware that the function
above is very vulnerable to multithreading problems; whenever you design
functions containing static variables you should keep multithreading issues in
mind.</FONT><BR></P></DIV>
<A NAME="Heading298"></A><FONT FACE = "Verdana"><H4 ALIGN="LEFT">
static class objects inside
functions<BR><A NAME="Index1703"></A><A NAME="Index1704"></A><A NAME="Index1705"></A><A NAME="Index1706"></A></H4></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The rules are the same for static objects
of user-defined types, including the fact that some initialization is required
for the object. However, assignment to zero has meaning only for built-in types;
user-defined types must be initialized with constructor calls. Thus, if you
don’t specify constructor arguments when you define the static object, the
class must have a default
constructor<A NAME="Index1707"></A><A NAME="Index1708"></A>. For
example,</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C10:StaticObjectsInFunctions.cpp</font>
#include <iostream>
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
<font color=#0000ff>class</font> X {
<font color=#0000ff>int</font> i;
<font color=#0000ff>public</font>:
X(<font color=#0000ff>int</font> ii = 0) : i(ii) {} <font color=#009900>// Default</font>
~X() { cout << <font color=#004488>"X::~X()"</font> << endl; }
};
<font color=#0000ff>void</font> f() {
<font color=#0000ff>static</font> X x1(47);
<font color=#0000ff>static</font> X x2; <font color=#009900>// Default constructor required</font>
}
<font color=#0000ff>int</font> main() {
f();
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The static objects of type <B>X</B>
inside <B>f( )</B> can be initialized either with the constructor argument
list or with the default constructor. This construction occurs the first time
control passes through the definition, and only the first time.</FONT><BR></P></DIV>
<A NAME="Heading299"></A><FONT FACE = "Verdana"><H4 ALIGN="LEFT">
Static object destructors</H4></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Destructors for static objects (that is,
all objects with static storage, not just local static objects as in the example
above) are called when <B>main( )</B> exits or when the Standard C library
function
<B>exit( )<A NAME="Index1709"></A><A NAME="Index1710"></A><A NAME="Index1711"></A>
</B>is explicitly called. In most implementations, <B>main( )</B> just
calls <B>exit( )</B> when it terminates. This means that it can be
dangerous to call <B>exit( )</B> inside a destructor because you can end up
with infinite recursion. Static object destructors are <I>not</I> called if you
exit the program using the Standard C library function
<B>abort( )<A NAME="Index1712"></A><A NAME="Index1713"></A><A NAME="Index1714"></A></B>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can specify actions to take place
when leaving <B>main( )</B> (or calling <B>exit( )</B>) by using the
Standard C library function
<B>atexit( )<A NAME="Index1715"></A><A NAME="Index1716"></A><A NAME="Index1717"></A></B>.
In this case, the functions registered by <B>atexit( ) </B>may be called
before the destructors for any objects constructed before leaving
<B>main( )</B> (or calling <B>exit( )</B>).</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Like ordinary destruction, destruction of
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -