⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ei21.htm

📁 一个非常适合初学者入门的有关c++的文档
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN" "http://www.w3.org/TR/REC-html40/frameset.dtd">
<HTML LANG="EN">
<HEAD>
<title>Effective C++, 2E | Item 21: Use const whenever possible</TITLE>
<LINK REL=STYLESHEET HREF=../INTRO/ECMEC.CSS>

<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/COOKIE.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript">var imagemax = 0; setCurrentMax(0);</SCRIPT>
<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/DINGBATS.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript">
var dingbase = "EI21_DIR.HTM";
var dingtext = "Item E21, P";
if (self == top) {
 top.location.replace(dingbase + this.location.hash);
}
</SCRIPT>

</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" ONLOAD="setResize()">
<!-- SectionName="E21: Use const whenever possible." -->
<A NAME="6003"></A>
<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./EI20_FR.HTM" TARGET="_top">Item 20: Differentiate among member functions, non-member functions, and friend functions.</A> &nbsp;&nbsp;<BR>&nbsp;&nbsp;Continue to <A HREF="./EI22_FR.HTM" TARGET="_top">Item 22: Prefer pass-by-reference to pass-by-value.</A></FONT></DIV>

<P><A NAME="dingp1"></A><A NAME="p91"></A><FONT ID="eititle">Item 21: &nbsp;Use <CODE>const</CODE> whenever possible.</FONT><SCRIPT>create_link(1);</SCRIPT>
</P>

<A NAME="6004"></A>
<P><A NAME="dingp2"></A>
The wonderful thing about <CODE>const</CODE> is that it allows you to specify a certain semantic constraint &#151; a particular object should <I>not</I> be modified &#151; and compilers will enforce that constraint. It allows you to communicate to both compilers and other programmers that a value should remain invariant. Whenever that is true, you should be sure to say so explicitly, because that way you enlist your compilers' aid in making sure the constraint isn't <NOBR>violated.<SCRIPT>create_link(2);</SCRIPT>
</NOBR></P>
<A NAME="6005"></A>
<P><A NAME="dingp3"></A>
The <CODE>const</CODE> keyword is remarkably versatile. Outside of classes, you can use it for global or namespace constants (see Items <A HREF="./EI1_FR.HTM#1790" TARGET="_top">1</A> and <A HREF="./EI47_FR.HTM#8299" TARGET="_top">47</A>) and for static objects (local to a file or a block). Inside classes, you can use it for both static and nonstatic data members (see also <A HREF="./EI12_FR.HTM#2071" TARGET="_top">Item 12</A>).<SCRIPT>create_link(3);</SCRIPT>
</P>
<A NAME="6016"></A>
<P><A NAME="dingp4"></A>
For pointers, you can specify whether the pointer itself is <CODE>const</CODE>, the data it points to is <CODE>const</CODE>, both, or <NOBR>neither:<SCRIPT>create_link(4);</SCRIPT>
</NOBR></P>
<A NAME="6017"></A>
<UL><PRE>
char *p              = "Hello";          // non-const pointer,
                                         // non-const data<A HREF="#223676"><sup>5</sup></A>
</PRE>
</UL><A NAME="6018"></A>
<UL><PRE>
const char *p        = "Hello";          // non-const pointer,
                                         // const data
</PRE>
</UL><A NAME="6019"></A>
<UL><PRE>
char * const p       = "Hello";          // const pointer,
                                         // non-const data
</PRE>
</UL><A NAME="6020"></A>
<UL><PRE>
const&#32;char&#32;*&#32;const&#32;p = "Hello";          // const pointer,
                                         // const data
</PRE>
</UL><A NAME="6021"></A>
<P><A NAME="dingp5"></A>
This syntax isn't quite as capricious as it looks. Basically, you mentally draw a vertical line through the asterisk of a pointer declaration, and if the word <CODE>const</CODE> appears to the left of the line, what's <I>pointed to</I> is constant; if the word <CODE>const</CODE> appears to the right of the line, the <I>pointer itself</I> is constant; if <CODE>const</CODE> appears on both sides of the line, both are <NOBR>constant.<SCRIPT>create_link(5);</SCRIPT>
</NOBR></P>
<A NAME="29440"></A>
<P><A NAME="dingp6"></A>
When what's pointed to is constant, some programmers list <CODE>const</CODE> before the type name. Others list it after the type name but before the asterisk. As a result, the following functions take the same parameter <NOBR>type:<SCRIPT>create_link(6);</SCRIPT>
</NOBR></P>
<A NAME="29438"></A>
<UL><PRE>class Widget { ... };
</PRE>
</UL><A NAME="29448"></A>
<UL><PRE>
void f1(const Widget *pw);      // f1 takes a pointer to a
                                // constant Widget object
</PRE>
</UL><A NAME="29449"></A>
<UL><PRE>
void f2(Widget const *pw);      // so does f2
</PRE>
</UL><A NAME="29450"></A>
<P><A NAME="dingp7"></A>
Because both forms exist in real code, you should accustom yourself to both of <NOBR>them.<SCRIPT>create_link(7);</SCRIPT>
</NOBR></P>
<A NAME="29437"></A>
<P><A NAME="dingp8"></A>
<A NAME="p92"></A><A NAME="p92"></A>Some of the most powerful uses of <CODE>const</CODE> stem from its application to function declarations. Within a function declaration, <CODE>const</CODE> can refer to the function's return value, to individual parameters, and, for member functions, to the function as a <NOBR>whole.<SCRIPT>create_link(8);</SCRIPT>
</NOBR></P>
<A NAME="16780"></A>
<P><A NAME="dingp9"></A>
Having a function return a constant value often makes it possible to reduce the incidence of client errors without giving up safety or efficiency. In fact, as <A HREF="./EI29_FR.HTM#6490" TARGET="_top">Item 29</A> demonstrates, using <CODE>const</CODE> with a return value can make it possible to <I>improve</I> the safety and efficiency of a function that would otherwise be <NOBR>problematic.<SCRIPT>create_link(9);</SCRIPT>
</NOBR></P>
<A NAME="16761"></A>
<P><A NAME="dingp10"></A>
For example, consider the declaration of the <CODE>operator*</CODE> function for rational numbers that is introduced in <A HREF="./EI19_FR.HTM#5887" TARGET="_top">Item 19</A>:<SCRIPT>create_link(10);</SCRIPT>
</P>
<A NAME="16795"></A>
<UL><PRE>const Rational operator*(const Rational&amp; lhs,
                         const Rational&amp; rhs);
</PRE>
</UL><A NAME="213395"></A>
<P><A NAME="dingp11"></A>
Many programmers squint when they first see this. Why should the result of <CODE>operator*</CODE> be a <CODE>const</CODE> object? Because if it weren't, clients would be able to commit atrocities like <NOBR>this:<SCRIPT>create_link(11);</SCRIPT>
</NOBR></P>
<A NAME="213396"></A>
<UL><PRE>Rational a, b, c;
</PRE>
</UL><A NAME="16800"></A>
<UL><PRE>...
</PRE>
</UL><A NAME="16801"></A>
<UL><PRE>
(a * b) = c;      // assign to the product
                  // of a*b!
</PRE>
</UL><A NAME="16804"></A>
<P><A NAME="dingp12"></A>
I don't know why any programmer would want to make an assignment to the product of two numbers, but I do know this: it would be flat-out illegal if <CODE>a</CODE>, <CODE>b</CODE>, and <CODE>c</CODE> were of a built-in type. One of the hallmarks of good user-defined types is that they avoid gratuitous behavioral incompatibilities with the built-ins, and allowing assignments to the product of two numbers seems pretty gratuitous to me. Declaring <CODE>operator*</CODE>'s return value <CODE>const</CODE> prevents it, and that's why It's The Right Thing To <NOBR>Do.<SCRIPT>create_link(12);</SCRIPT>
</NOBR></P>
<A NAME="6052"></A>
<P><A NAME="dingp13"></A>
There's nothing particularly new about <CODE>const</CODE> parameters &#151; they act just like local <CODE>const</CODE> objects. (See <A HREF="../MEC/MI19_FR.HTM#41177" TARGET="_top">Item M19</A>, however, for a discussion of how <CODE>const</CODE> parameters can lead to the creation of temporary objects.) Member functions that are <CODE>const</CODE>, however, are a different <NOBR>story.<SCRIPT>create_link(13);</SCRIPT>
</NOBR></P>
<A NAME="150971"></A>
<P><A NAME="dingp14"></A>
The purpose of <CODE>const</CODE> member functions, of course, is to specify which member functions may be invoked on <CODE>const</CODE> objects. Many people overlook the fact that member functions differing <I>only</I> in their constness can be overloaded, however, and this is an important feature of C++. Consider the <CODE>String</CODE> class once <NOBR>again:<SCRIPT>create_link(14);</SCRIPT>
</NOBR></P>
<A NAME="6058"></A>
<UL><PRE><A NAME="p93"></A>class String {
public:
</PRE>
</UL><A NAME="6060"></A>
<UL><PRE>  ...
</PRE>
</UL><A NAME="6061"></A>
<UL><PRE>  // operator[] for non-const objects
  char&amp; operator[](int position)
  { return data[position]; }
</PRE>
</UL><A NAME="6062"></A>
<UL><PRE>  // operator[] for const objects
  const char&amp; operator[](int position) const
  { return data[position]; }
</PRE>
</UL><A NAME="16377"></A>
<UL><PRE>private:
  char *data;
};
</PRE>
</UL><A NAME="6063"></A>
<UL><PRE>String s1 = "Hello";
cout &lt;&lt; s1[0];                  // calls non-const
                                // String::operator[]
const String s2 = "World";
cout &lt;&lt; s2[0];                  // calls const
                                // String::operator[]
</PRE>
</UL><A NAME="6064"></A>
<P><A NAME="dingp15"></A>
By overloading <CODE>operator[]</CODE> and giving the different versions different return values, you are able to have <CODE>const</CODE> and non-<CODE>const</CODE> <CODE>String</CODE>s handled <NOBR>differently:<SCRIPT>create_link(15);</SCRIPT>
</NOBR></P>
<A NAME="6065"></A>
<UL><PRE>
String s = "Hello";                      // non-const String object
</PRE>
</UL><A NAME="17906"></A>
<UL><PRE>
cout &lt;&lt; s[0];                            // fine &#151; reading a
                                         // non-const String
</PRE>
</UL><A NAME="17912"></A>
<UL><PRE>
s[0] = 'x';                              // fine &#151; writing a
                                         // non-const String
</PRE>
</UL><A NAME="6066"></A>
<UL><PRE>
const String cs = "World";               // const String object
</PRE>
</UL><A NAME="6068"></A>
<UL><PRE>
cout &lt;&lt; cs[0];                           // fine &#151; reading a
                                         // const String
</PRE>
</UL><A NAME="6070"></A>
<UL><PRE>
cs[0] = 'x';                             // error! &#151; writing a
                                         // const String
</PRE>
</UL><A NAME="6071"></A>
<P><A NAME="dingp16"></A>
By the way, note that the error here has only to do with the <I>return value</I> of the <CODE>operator[]</CODE> that is called; the calls to <CODE>operator[]</CODE> themselves are all fine. The error arises out of an attempt to make an assignment to a <CODE>const</CODE> <CODE>char&amp;</CODE>, because that's the return value from the <CODE>const</CODE> version of <CODE>operator[]</CODE>.<SCRIPT>create_link(16);</SCRIPT>
</P>
<A NAME="6075"></A>
<P><A NAME="dingp17"></A>
Also note that the return type of the non-<CODE>const</CODE> <CODE>operator[]</CODE> must be a <I>reference</I> to a <CODE>char</CODE> &#151; a <CODE>char</CODE> itself will not do. If <CODE>operator[]</CODE> did return a simple <CODE>char</CODE>, statements like this wouldn't <NOBR>compile:<SCRIPT>create_link(17);</SCRIPT>
</NOBR></P>
<A NAME="6076"></A>
<UL><PRE>s[0] = 'x';
</PRE>
</UL><A NAME="6077"></A>
<P><A NAME="dingp18"></A>
<A NAME="p94"></A>That's because it's never legal to modify the return value of a function that returns a built-in type. Even if it were legal, the fact that C++ returns objects by value (see <A HREF="./EI22_FR.HTM#6133" TARGET="_top">Item 22</A>) would mean that a <I>copy</I> of <CODE>s.data[0]</CODE> would be modified, not <CODE>s.data[0]</CODE> itself, and that's not the behavior you want, <NOBR>anyway.<SCRIPT>create_link(18);</SCRIPT>
</NOBR></P>
<A NAME="6081"></A>
<P><A NAME="dingp19"></A>
Let's take a brief time-out for philosophy. What exactly does it mean for a member function to be <CODE>const</CODE>? There are two prevailing notions: bitwise constness and conceptual <NOBR>constness.<SCRIPT>create_link(19);</SCRIPT>
</NOBR></P>
<A NAME="6084"></A>
<P><A NAME="dingp20"></A>
The bitwise <CODE>const</CODE> camp believes that a member function is <CODE>const</CODE> if and only if it doesn't modify any of the object's data members (excluding those that are static), i.e., if it doesn't modify any of the bits inside the object. The nice thing about bitwise constness is that it's easy to detect violations: compilers just look for assignments to data members. In fact, bitwise constness is C++'s definition of constness, and a <CODE>const</CODE> member function isn't allowed to modify any of the data members of the object on which it is <NOBR>invoked.<SCRIPT>create_link(20);</SCRIPT>
</NOBR></P>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -