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

📄 ec4.htm

📁 一个非常适合初学者入门的有关c++的文档
💻 HTM
📖 第 1 页 / 共 5 页
字号:
</PRE>
</UL><A NAME="5991"></A>
<P><A NAME="dingp81"></A>
Still not convinced? Then it's time to bring out the big gun: functional abstraction. If you implement access to a data member through a function, you can later replace the data member with a computation, and nobody using your class will be any the <NOBR>wiser.<SCRIPT>create_link(81);</SCRIPT>
</NOBR></P>
<A NAME="5992"></A>
<P><A NAME="dingp82"></A>
<A NAME="p90"></A>For example, suppose you are writing an application in which some automated equipment is monitoring the speed of passing cars. As each car passes, its speed is computed, and the value is added to a collection of all the speed data collected so <NOBR>far:<SCRIPT>create_link(82);</SCRIPT>
</NOBR></P>
<A NAME="5994"></A>
<UL><PRE>class SpeedDataCollection {
public:
  void addValue(int speed);       // add a new data value
</PRE>
</UL><A NAME="5995"></A>
<UL><PRE>  double averageSoFar() const;    // return average speed
};
</PRE>
</UL><A NAME="5996"></A>
<P><A NAME="dingp83"></A>
Now consider the implementation of the member function <CODE>averageSoFar</CODE> (see also <A HREF="../MEC/MC4_FR.HTM#41124" TARGET="_top">Item M18</A>). One way to implement it is to have a data member in the class that is a running average of all the speed data so far collected. Whenever <CODE>averageSoFar</CODE> is called, it just returns the value of that data member. A different approach is to have <CODE>averageSoFar</CODE> compute its value anew each time it's called, something it could do by examining each data value in the collection. (For a more general discussion of these two approaches, see Items <A HREF="../MEC/MC4_FR.HTM#41011" TARGET="_top">M17</A> and <A HREF="../MEC/MC4_FR.HTM#41124" TARGET="_top">M18</A>.)<SCRIPT>create_link(83);</SCRIPT>
</P>
<A NAME="5997"></A>
<P><A NAME="dingp84"></A>
The first approach &#151; keeping a running average &#151; makes each <CODE>SpeedDataCollection</CODE> object bigger, because you have to allocate space for the data member holding the running average. However, <CODE>averageSoFar</CODE> can be implemented very efficiently; it's just an inline function (see <A HREF="./EC5_FR.HTM#6729" TARGET="_top">Item 33</A>) that returns the value of the data member. Conversely, computing the average whenever it's requested will make <CODE>averageSoFar</CODE> run slower, but each <CODE>SpeedDataCollection</CODE> object will be <NOBR>smaller.<SCRIPT>create_link(84);</SCRIPT>
</NOBR></P>
<A NAME="5999"></A>
<P><A NAME="dingp85"></A>
Who's to say which is best? On a machine where memory is tight, and in an application where averages are needed only infrequently, computing the average each time is a better solution. In an application where averages are needed frequently, speed is of the essence, and memory is not an issue, keeping a running average is preferable. The important point is that by accessing the average through a member function, you can use <I>either</I> implementation, a valuable source of flexibility that you wouldn't have if you made a decision to include the running average data member in the public <NOBR>interface.<SCRIPT>create_link(85);</SCRIPT>
</NOBR></P>
<A NAME="6001"></A>
<P><A NAME="dingp86"></A>
The upshot of all this is that you're just asking for trouble by putting data members in the public interface, so play it safe by hiding all your data members behind a wall of functional abstraction. If you do it <I>now</I>, we'll throw in consistency and fine-grained access control at no extra <NOBR>cost!<SCRIPT>create_link(86);</SCRIPT>
</NOBR></P>
<!-- SectionName="E21: Use const whenever possible" -->
<A NAME="6003"></A><A NAME="p91"></A>

<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="#5976">Item 20: Differentiate among member functions, non-member functions, and friend functions.</A>
                            <BR>Continue to <A HREF="#6133">Item 22: Prefer pass-by-reference to pass-by-value.</A></FONT></DIV>


<P><A NAME="dingp87"></A><FONT ID="eititle">Item 21: Use <CODE>const</CODE> whenever possible.</FONT><SCRIPT>create_link(87);</SCRIPT>
</P>

<A NAME="6004"></A>
<P><A NAME="dingp88"></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(88);</SCRIPT>
</NOBR></P>
<A NAME="6005"></A>
<P><A NAME="dingp89"></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="./EC1_FR.HTM#1790" TARGET="_top">1</A> and <A HREF="./EC7_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="./EC3_FR.HTM#2071" TARGET="_top">Item 12</A>).<SCRIPT>create_link(89);</SCRIPT>
</P>
<A NAME="6016"></A>
<P><A NAME="dingp90"></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(90);</SCRIPT>
</NOBR></P>
<A NAME="6017"></A>
<UL><PRE>
char *p              = "Hello";          // non-const pointer,
                                         // non-const data<A HREF="#223676"><sup>4</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="dingp91"></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(91);</SCRIPT>
</NOBR></P>
<A NAME="29440"></A>
<P><A NAME="dingp92"></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(92);</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="dingp93"></A>
Because both forms exist in real code, you should accustom yourself to both of <NOBR>them.<SCRIPT>create_link(93);</SCRIPT>
</NOBR></P>
<A NAME="29437"></A>
<P><A NAME="dingp94"></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(94);</SCRIPT>
</NOBR></P>
<A NAME="16780"></A>
<P><A NAME="dingp95"></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="./EC5_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(95);</SCRIPT>
</NOBR></P>
<A NAME="16761"></A>
<P><A NAME="dingp96"></A>
For example, consider the declaration of the <CODE>operator*</CODE> function for rational numbers that is introduced in <A HREF="#5887">Item 19</A>:<SCRIPT>create_link(96);</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="dingp97"></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(97);</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="dingp98"></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(98);</SCRIPT>
</NOBR></P>
<A NAME="6052"></A>
<P><A NAME="dingp99"></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/MC4_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(99);</SCRIPT>
</NOBR></P>
<A NAME="150971"></A>
<P><A NAME="dingp100"></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(100);</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="dingp101"></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(101);</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>

⌨️ 快捷键说明

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