📄 chapter08.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:35
Translation Platform:Win32
Number of Output files:22
This File:Chapter08.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>8: Constants</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="Chapter07.html">Previous Chapter</a> ]
[ <a href="Contents.html">Table of Contents</a> ]
[ <a href="DocIndex.html">Index</a> ]
[ <a href="Chapter09.html">Next Chapter</a> ]
</FONT>
</CENTER>
</P></DIV><A NAME="_Toc472654876"></A><FONT FACE = "Verdana"><H1 ALIGN="LEFT">
8: Constants</H1></FONT>
<A NAME="Heading247"></A><FONT FACE = "Verdana"><H1 ALIGN="LEFT">
</H1></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Verdana" SIZE=4>The concept of <I>constant</I>
(expressed by the <A NAME="Index1446"></A><B>const</B> keyword) was created to
allow the programmer to </FONT><BR><FONT FACE="Verdana" SIZE=4>draw a line
between what changes and what doesn’t. This provides safety and control in
a C++ </FONT><BR><FONT FACE="Verdana" SIZE=4>programming
project.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Since its origin, <B>const</B> has taken
on a number of different purposes. In the meantime it trickled back into the C
language where its meaning was changed. All this can seem a bit confusing at
first, and in this chapter you’ll learn when, why, and how to use the
<B>const</B> keyword. At the end there’s a discussion of <B>volatile</B>,
which is a near cousin to <B>const</B> (because they both concern change) and
has identical syntax.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The first motivation for <B>const</B>
seems to have been to eliminate the use of preprocessor <B>#define</B>s for
value substitution. It has since been put to use for pointers, function
arguments, return types, class objects and member functions. All of these have
slightly different but conceptually compatible meanings and will be looked at in
separate sections in this
chapter.</FONT><A NAME="_Toc305628675"></A><A NAME="_Toc312373903"></A><A NAME="_Toc472654877"></A><BR></P></DIV>
<A NAME="Heading248"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Value substitution</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">When programming in
<A NAME="Index1447"></A>C, the preprocessor <A NAME="Index1448"></A>is liberally
used to create macros and to substitute values.
<A NAME="Index1449"></A><A NAME="Index1450"></A> Because the preprocessor simply
does text replacement and has no concept nor facility for type checking,
preprocessor value substitution introduces subtle problems that can be avoided
in C++ by using <B>const</B> <A NAME="Index1451"></A>values.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The typical use of the preprocessor to
substitute values for names in C looks like this:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>#define BUFSIZE 100</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia"><B>BUFSIZE</B> is a name that only exists
during preprocessing, therefore it doesn’t occupy storage and can be
placed in a header file to provide a single value for all translation units that
use it. It’s very important for code maintenance to use value substitution
instead of so-called “magic numbers<A NAME="Index1452"></A>.” If you
use magic numbers in your code, not only does the reader have no idea where the
numbers come from or what they represent, but if you decide to change a value,
you must perform hand editing, and you have no trail to follow to ensure you
don’t miss one of your values (or accidentally change one you
shouldn’t).</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Most of the time, <B>BUFSIZE</B> will
behave like an ordinary variable, but not all the time. In addition,
there’s no type information. This can hide bugs that are very difficult to
find. C++ uses <B>const</B> to eliminate these problems by bringing value
substitution into the domain of the compiler. Now you can say</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>const</font> <font color=#0000ff>int</font> bufsize = 100;</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can use <B>bufsize </B>anyplace where
the compiler must know the value at compile time. The compiler can use
<B>bufsize</B> <A NAME="Index1453"></A><A NAME="Index1454"></A>to perform
<I>constant folding<A NAME="Index1455"></A></I>, which means the compiler will
reduce a complicated constant expression to a simple one by performing the
necessary calculations at compile time. This is especially important in array
definitions:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>char</font> buf[bufsize];</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can use <B>const</B> for all the
built-in types (<B>char</B>, <B>int</B>, <B>float</B>, and <B>double</B>) and
their variants (as well as class objects, as you’ll see later in this
chapter). Because of subtle bugs that the preprocessor might introduce, you
should always use <B>const</B> instead of <B>#define<A NAME="Index1456"></A></B>
value
substitution.</FONT><A NAME="_Toc312373904"></A><A NAME="_Toc472654878"></A><BR></P></DIV>
<A NAME="Heading249"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
const in header files</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">To use <B>const</B> instead of
<A NAME="Index1457"></A><B>#define</B>, you must be able to place <B>const</B>
definitions inside header files <A NAME="Index1458"></A>
<A NAME="Index1459"></A>as you can with <B>#define</B>. This way, you can place
the definition for a <B>const</B> in a single place and distribute it to
translation units by including the header file. A <B>const</B> in C++ defaults
to <I>internal linkage<A NAME="Index1460"></A><A NAME="Index1461"></A></I>; that
is, it is visible only within the file where it is defined and cannot be seen at
link time by other translation units. You must always assign a value to a
<B>const</B> when you define it, <I>except</I> when you make an explicit
declaration using
<A NAME="Index1462"></A><B>extern<A NAME="Index1463"></A></B>:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>extern</font> <font color=#0000ff>const</font> <font color=#0000ff>int</font> bufsize;</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><A NAME="Index1464"></A><FONT FACE="Georgia">Normally, the C++
compiler avoids creating storage for a <B>const</B>, but instead holds the
definition in its symbol table. When you use <B>extern</B> with <B>const</B>,
however, you<B> </B>force storage to be allocated (this is also true for certain
other cases, such as taking the address of a <B>const</B>). Storage must be
allocated because <B>extern</B> says “use external linkage,” which
means that several translation units must be able to refer to the item, which
requires it to have storage. </FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In the ordinary case, when <B>extern</B>
is not part of the definition, no <A NAME="Index1465"></A>storage is allocated.
When the <B>const</B> is used, it is simply folded in at compile
time.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The goal of never allocating storage for
a <B>const</B> also fails with complicated structures. Whenever the compiler
must allocate storage, constant folding is prevented (since there’s no way
for the compiler to know for sure what the value of that storage is – if
it could know that, it wouldn’t need to allocate the
storage).</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Because the compiler cannot always avoid
allocating storage for a <B>const</B>, <B>const</B> definitions <I>must</I>
default to internal linkage, that is, linkage only <I>within</I> that particular
translation unit. Otherwise, linker errors would occur with complicated
<B>const</B>s because they cause storage to be allocated in multiple <B>cpp</B>
files. The linker would then see the same definition in multiple object files,
and complain. Because a <B>const</B> defaults to internal linkage, the linker
doesn’t try to link those definitions across translation units, and there
are no collisions. With built-in types, which are used in the majority of cases
involving constant expressions, the compiler can always perform constant
folding.</FONT><A NAME="_Toc312373905"></A><A NAME="_Toc472654879"></A><BR></P></DIV>
<A NAME="Heading250"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Safety consts</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The use of
<A NAME="Index1466"></A><B>const</B> is not limited to replacing <B>#define</B>s
in constant expressions. If you initialize a variable with a value that is
produced at runtime and you know it will not change for the lifetime of that
variable, it is good programming practice to make it a <B>const</B> so the
compiler will give you an error message if you accidentally try to change it.
Here’s an example:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C08:Safecons.cpp</font>
<font color=#009900>// Using const for safety</font>
#include <iostream>
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
<font color=#0000ff>const</font> <font color=#0000ff>int</font> i = 100; <font color=#009900>// Typical constant</font>
<font color=#0000ff>const</font> <font color=#0000ff>int</font> j = i + 10; <font color=#009900>// Value from const expr</font>
<font color=#0000ff>long</font> address = (<font color=#0000ff>long</font>)&j; <font color=#009900>// Forces storage</font>
<font color=#0000ff>char</font> buf[j + 10]; <font color=#009900>// Still a const expression</font>
<font color=#0000ff>int</font> main() {
cout << <font color=#004488>"type a character & CR:"</font>;
<font color=#0000ff>const</font> <font color=#0000ff>char</font> c = cin.get(); <font color=#009900>// Can't change</font>
<font color=#0000ff>const</font> <font color=#0000ff>char</font> c2 = c + 'a';
cout << c2;
<font color=#009900>// ...</font>
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can see that <B>i</B> is a
compile-time <B>const</B>, but <B>j</B> is calculated from <B>i</B>. However,
because <B>i</B> is a <A NAME="Index1467"></A><B>const</B>, the calculated value
for <B>j</B> still comes from a constant expression and is itself a compile-time
constant. The very next line requires the address of <B>j</B> and therefore
forces the compiler to allocate storage for <B>j</B>. Yet this doesn’t
prevent the use of <B>j</B> in the determination of the size of <B>buf</B>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -