📄 chapter10.html
字号:
static objects
<A NAME="Index1718"></A><A NAME="Index1719"></A><A NAME="Index1720"></A>occurs
in the reverse order of initialization. However, only objects that have been
constructed are destroyed. Fortunately, the C++ development tools keep track of
initialization order and the objects that have been constructed. Global objects
are always
constructed<A NAME="Index1721"></A><A NAME="Index1722"></A><A NAME="Index1723"></A>
before <B>main( )</B> is entered and destroyed as <B>main( )</B>
exits, but if a function containing a local static object
<A NAME="Index1724"></A><A NAME="Index1725"></A><A NAME="Index1726"></A>is never
called, the constructor for that object is never executed, so the destructor is
also not executed. For example,</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C10:StaticDestructors.cpp</font>
<font color=#009900>// Static object destructors</font>
#include <fstream>
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
ofstream out(<font color=#004488>"statdest.out"</font>); <font color=#009900>// Trace file</font>
<font color=#0000ff>class</font> Obj {
<font color=#0000ff>char</font> c; <font color=#009900>// Identifier</font>
<font color=#0000ff>public</font>:
Obj(<font color=#0000ff>char</font> cc) : c(cc) {
out << <font color=#004488>"Obj::Obj() for "</font> << c << endl;
}
~Obj() {
out << <font color=#004488>"Obj::~Obj() for "</font> << c << endl;
}
};
Obj a('a'); <font color=#009900>// Global (static storage)</font>
<font color=#009900>// Constructor & destructor always called</font>
<font color=#0000ff>void</font> f() {
<font color=#0000ff>static</font> Obj b('b');
}
<font color=#0000ff>void</font> g() {
<font color=#0000ff>static</font> Obj c('c');
}
<font color=#0000ff>int</font> main() {
out << <font color=#004488>"inside main()"</font> << endl;
f(); <font color=#009900>// Calls static constructor for b</font>
<font color=#009900>// g() not called</font>
out << <font color=#004488>"leaving main()"</font> << endl;
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In <B>Obj</B>, the <B>char c</B> acts as
an identifier so the constructor and destructor can print out information about
the object they’re working on. The <B>Obj a</B> is a global object, so the
constructor is always called for it before <B>main( )</B> is entered, but
the constructors for the <B>static Obj b</B> inside <B>f( )</B> and the
<B>static Obj c</B> inside <B>g( )</B> are called only if those functions
are called.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">To demonstrate which constructors and
destructors are called, only <B>f( )</B> is called. The output of the
program is</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>Obj::Obj() <font color=#0000ff>for</font> a
inside main()
Obj::Obj() <font color=#0000ff>for</font> b
leaving main()
Obj::~Obj() <font color=#0000ff>for</font> b
Obj::~Obj() <font color=#0000ff>for</font> a</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The constructor for <B>a</B> is called
before <B>main( )</B> is entered, and the constructor for <B>b</B> is
called only because <B>f( )</B> is called. When <B>main( )</B> exits,
the destructors for the objects that have been constructed are called in reverse
order of their construction. This means that if <B>g( )</B> <I>is</I>
called, the order in which the destructors for <B>b</B> and <B>c</B> are called
depends on whether <B>f( )</B> or <B>g( ) </B>is called
first.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Notice that the trace file
<B>ofstream</B> object <B>out</B> is also a static object – since it is
defined outside of all functions, it lives in the static storage
area<A NAME="Index1727"></A>. It is important that its definition (as opposed to
an <B>extern</B> declaration) appear at the beginning of the file, before there
is any possible use of <B>out</B>. Otherwise, you’ll be using an object
before it is properly initialized.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In C++, the constructor for a global
static object is called before <B>main( )</B> is entered, so you now have a
simple and portable way to execute code before entering
<B>main( )<A NAME="Index1728"></A><A NAME="Index1729"></A></B> and to
execute code with the destructor after exiting
<B>main( )<A NAME="Index1730"></A><A NAME="Index1731"></A><A NAME="Index1732"></A></B>.
In C, this was always a trial that required you to root around in the compiler
vendor’s assembly-language startup
code.</FONT><A NAME="_Toc312373943"></A><A NAME="_Toc472654917"></A><BR></P></DIV>
<A NAME="Heading300"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Controlling linkage<BR><A NAME="Index1733"></A><A NAME="Index1734"></A></H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Ordinarily, any name at <I>file scope</I>
<A NAME="Index1735"></A><A NAME="Index1736"></A>(that is, not nested inside a
class or function) is visible throughout all translation units in a program.
This is often called <I>external linkage</I>
<A NAME="Index1737"></A><A NAME="Index1738"></A>because at link time the name is
visible to the linker everywhere, external to that translation unit. Global
variables and ordinary functions have external linkage.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">There are times when you’d like to
limit the visibility of a name. You might like to have a variable at file scope
so all the functions in that file can use it, but you don’t want functions
outside that file to see or access that variable, or to inadvertently cause name
clashes with identifiers outside the file.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">An object or function name at file scope
that is explicitly declared <B>static</B> is local to its translation unit (in
the terms of this book, the<B> cpp</B> file where the declaration occurs). That
name has <I>internal
linkage<A NAME="Index1739"></A><A NAME="Index1740"></A></I>. This means that you
can use the same name in other translation units without a name
clash.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">One advantage to internal linkage is that
the name can be placed in a <A NAME="Index1741"></A>header file without worrying
that there will be a clash at link time. Names that are commonly placed in
header files, such as <B>const</B> definitions and <B>inline</B> functions,
default to internal linkage. (However, <B>const</B> defaults to internal linkage
only in C++; in C it defaults to external linkage.) Note that linkage refers
only to elements that have addresses at link/load time; thus, class declarations
and local variables have no
linkage<A NAME="Index1742"></A><A NAME="Index1743"></A>.</FONT><BR></P></DIV>
<A NAME="Heading301"></A><FONT FACE = "Verdana"><H4 ALIGN="LEFT">
Confusion</H4></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here’s an example of how the two
meanings of <A NAME="Index1744"></A><B>static</B> <A NAME="Index1745"></A>can
cross over each other. All global objects implicitly have static storage
class<A NAME="Index1746"></A>, so if you say (at file scope),</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>int</font> a = 0;</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">then storage for <B>a</B> will be in the
program’s static data area, and the initialization for <B>a</B> will occur
once, before <B>main( )</B> is entered. In addition, the visibility of
<B>a</B> is global across all translation units. In terms of visibility, the
opposite of <B>static</B> (visible only in this translation unit) is
<A NAME="Index1747"></A><B>extern<A NAME="Index1748"></A><A NAME="Index1749"></A></B>,
which explicitly states that the visibility of the name is across all
translation units. So the definition above is equivalent to
saying</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>extern</font> <font color=#0000ff>int</font> a = 0;</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">But if you say instead,</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>static</font> <font color=#0000ff>int</font> a = 0;</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">all you’ve done is change the
visibility, so <B>a</B> has internal linkage. The storage class is unchanged
– the object resides in the static data area whether the visibility is
<B>static</B> or <B>extern</B>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Once you get into local variables,
<B>static</B> stops altering the visibility and instead alters the storage
class. </FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">If you declare what appears to be a local
variable as <B>extern</B>, it means that the storage exists elsewhere (so the
variable is actually global to the function). For example:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C10:LocalExtern.cpp</font>
<font color=#009900>//{L} LocalExtern2</font>
#include <iostream>
<font color=#0000ff>int</font> main() {
<font color=#0000ff>extern</font> <font color=#0000ff>int</font> i;
std::cout << i;
} <font color=#009900>///:~</font>
<font color=#009900>//: C10:LocalExtern2.cpp {O}</font>
<font color=#0000ff>int</font> i = 5;
<font color=#009900>///:~ </font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">With function names (for non-member
functions), <B>static</B> and <B>extern</B> can only alter visibility, so if you
say</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>extern</font> <font color=#0000ff>void</font> f();</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">it’s the same as the unadorned
declaration</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>void</font> f();</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">and if you say,</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>static</font> <font color=#0000ff>void</font> f();</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">it means <B>f( )</B> is visible only
within this translation unit – this is sometimes called <I>file
static<A NAME="Index1750"></A><A NAME="Index1751"></A></I>.</FONT><A NAME="_Toc312373944"></A><A NAME="_Toc472654918"></A><BR></P></DIV>
<A NAME="Heading302"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Other storage class specifiers</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You will see <B>static</B> and
<B>extern</B> used commonly. There are two other storage class specifiers that
occur less often. The <A NAME="Index1752"></A><B>auto</B>
<A NAME="Index1753"></A><A NAME="Index1754"></A>specifier is almost never used
because it tells the compiler that this is a local variable. <B>auto</B> is
short for “automatic” and it refers to the way the compiler
automatically allocates storage for the variable. The compiler can always
determine this fact from the context in which the variable is defined, so
<B>auto</B> is redundant.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">A <A NAME="Index1755"></A><B>register</B>
<A NAME="Index1756"></A><A NAME="Index1757"></A>variable is a local
(<B>auto</B>) variable, along with a hint to the compiler that this particular
variable will be heavily used so the compiler ought to keep it in a register if
it can. Thus, it is an optimization aid. Various compilers respond differently
to this hint; they have the option to ignore it. If you take the address of the
variable, the <B>register</B> specifier will almost certainly be ignored. You
should avoid using <B>register</B> because the compiler can usually do a better
job of optimization than
you.</FONT><A NAME="_Toc305593220"></A><A NAME="_Toc305628692"></A><A NAME="_Toc312373945"></A><A NAME="_Toc472654919"></A><BR></P></DIV>
<A NAME="Heading303"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Namespaces</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Although names can be nested inside
classes, the names of global functions, global variables, and classes are still
in a single global name space. The <B>static</B> keyword gives you some control
over this by allowing you to give variables and functions internal linkage (that
is, to make them file static<A NAME="Index1758"></A><A NAME="Index1759"></A>).
But in a large project, lack of control over the global name space can cause
problems. To solve these problems for classes, vendors often create long
complicated names that are unlikely to clash, but then you’re stuck typing
those names. (A <A NAME="Index1760"></A><B>typedef</B> is often used to simplify
this.) It’s not an elegant, language-supported solution.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can subdivide the global name space
into more manageable pieces using the <I>namespace</I>
<A NAME="Index1761"></A>feature of C++. The
<A NAME="Index1762"></A><B>namespace</B> keyword, similar to <B>class</B>,
<B>struct</B>, <B>enum</B>, and <B>union</B>, puts the names of its members in a
distinct space. While the other keywords have additional purposes, the creation
of a new name space is the only purpose for
<B>namespace</B>.</FONT><A NAME="_Toc312373946"></A><A NAME="_Toc472654920"></A><BR></P></DIV>
<A NAME="Heading304"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Creating a namespace</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The creation of a namespace is notably
similar to the creation of a <B>class</B>:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C10:MyLib.cpp</font>
<font color=#0000ff>namespace</font> MyLib {
<font color=#009900>// Declarations</font>
}
<font color=#0000ff>int</font> main() {} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -