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

📄 ec5.htm

📁 一个非常适合初学者入门的有关c++的文档
💻 HTM
📖 第 1 页 / 共 5 页
字号:
};
</PRE>
</UL><A NAME="6623"></A>
<UL><PRE>Address *addrPtr =
  scott.personAddress();        // same problem as above
</PRE>
</UL><A NAME="6624"></A>
<P><A NAME="dingp43"></A>
With pointers, however, you have to worry not only about data members, but also about member <I>functions</I>. That's because it's possible to return a pointer to a member <NOBR>function:<SCRIPT>create_link(43);</SCRIPT>
</NOBR></P>
<A NAME="6626"></A>
<UL><PRE>class Person;                   // forward declaration
</PRE>
</UL><A NAME="19356"></A>
<UL><PRE>// PPMF = "pointer to Person member function"
typedef void (Person::*PPMF)();
</PRE>
</UL><A NAME="6628"></A>
<UL><PRE>class Person {
public:
  static PPMF verificationFunction()
  { return &amp;Person::verifyAddress; }
</PRE>
</UL><A NAME="6632"></A>
<UL><PRE>  ...
</PRE>
</UL><A NAME="18305"></A>
<UL><PRE>private:
  Address address;
</PRE>
</UL><A NAME="18307"></A>
<UL><PRE>  void verifyAddress();
</PRE>
</UL><A NAME="19361"></A>
<UL><PRE>};
</PRE>
</UL><A NAME="6635"></A>
<A NAME="dingp44"></A><P>
If you're not used to socializing with pointers to member functions and typedefs thereof, the declaration for <CODE>Person::verificationFunction</CODE> may seem daunting. Don't be intimidated. All it says <NOBR>is<SCRIPT>create_link(44);</SCRIPT>
</NOBR></P>
<UL><A NAME="6636"></A>
<A NAME="dingp45"></A><LI><CODE>verificationFunction</CODE> is a member function that takes no parameters;<SCRIPT>create_link(45);</SCRIPT>

<A NAME="6637"></A>
<A NAME="dingp46"></A><LI>its return value is a pointer to a member function of the <CODE>Person</CODE> class;<SCRIPT>create_link(46);</SCRIPT>

<A NAME="6638"></A>
<A NAME="dingp47"></A><LI>the pointed-to function (i.e., <CODE>verificationFunction</CODE>'s return value) takes no parameters and returns nothing, i.e., <CODE>void</CODE>.<SCRIPT>create_link(47);</SCRIPT>

</UL>
<A NAME="6640"></A>
<P><A NAME="dingp48"></A>
As for the word <CODE>static</CODE>, that means what it always means in a member declaration: there is only one copy of the member for the entire class, and the member can be accessed without an object. For the complete story, consult your favorite introductory C++ textbook. (If your favorite introductory C++ textbook doesn't discuss static members, carefully <A NAME="p131"></A>tear out all its pages and recycle them. Dispose of the book's cover in an environmentally sound manner, then borrow or buy a better <NOBR>textbook.)<SCRIPT>create_link(48);</SCRIPT>
</NOBR></P>
<A NAME="222559"></A>
<P><A NAME="dingp49"></A>
In this last example, <CODE>verifyAddress</CODE> is a private member function, indicating that it's really an implementation detail of the class; only class members should know about it (and friends, too, of course). However, the public member function <CODE>verificationFunction</CODE> returns a pointer to <CODE>verifyAddress</CODE>, so clients can again pull this kind of <NOBR>thing:<SCRIPT>create_link(49);</SCRIPT>
</NOBR></P><A NAME="6642"></A>
<UL><PRE>PPMF pmf = scott.verificationFunction();
</PRE>
</UL><A NAME="6643"></A>
<UL><PRE>
(scott.*pmf)();                     // same as calling
                                    // scott.verifyAddress
</PRE>
</UL><A NAME="6644"></A>
<P><A NAME="dingp50"></A>
Here, <CODE>pmf</CODE> has become a synonym for <CODE>Person::verifyAddress</CODE>, with the crucial difference that there are no restrictions on its <NOBR>use.<SCRIPT>create_link(50);</SCRIPT>
</NOBR></P>
<A NAME="6645"></A>
<P><A NAME="dingp51"></A>
In spite of the foregoing discussion, you may someday be faced with a situation in which, pressed to achieve performance constraints, you honestly need to write a member function that returns a reference or a pointer to a less-accessible member. At the same time, however, you won't want to sacrifice the access restrictions that <CODE>private</CODE> and <CODE>protected</CODE> afford you. In those cases, you can almost always achieve both goals by returning a pointer or a reference to a <CODE>const</CODE> object. For details, take a look at <A HREF="./EC4_FR.HTM#6003" TARGET="_top">Item 21</A>.<SCRIPT>create_link(51);</SCRIPT>
</P>
<!-- SectionName="E31: Avoid hazardous reference returns" -->
<A NAME="6650"></A><A NAME="6651"></A>

<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="#6599">Item 30: Avoid member functions that return non-const pointers or references to members less accessible than themselves.</A>
                            <BR>Continue to <A HREF="#25939">Item 32: Postpone variable definitions as long as possible.</A></FONT></DIV>


<P><A NAME="dingp52"></A><FONT ID="eititle">Item 31: &nbsp;Never return a reference to a local object or to a dereferenced pointer initialized by <CODE>new</CODE> within the function.</FONT><SCRIPT>create_link(52);</SCRIPT>
</P>

<P><A NAME="dingp53"></A>
This Item may sound complicated, but it's not. It's simple common sense. Really. Honest. <I>Trust me</I>.<SCRIPT>create_link(53);</SCRIPT>
</P>
<A NAME="6652"></A>
<P><A NAME="dingp54"></A>
Consider first the matter of returning a reference to a local object. The problem here is that local objects are just that, <I>local</I>. That means they're constructed when they're defined, and they're destructed when they go out of scope. Their scope, however, is that of the function body in which they're located. When the function returns, control leaves its scope, so the objects local to that function are automatically destructed. As a result, if you return a reference to a local object, that local object has been destructed before the caller of the function ever gets its computational hands on <NOBR>it.<SCRIPT>create_link(54);</SCRIPT>
</NOBR></P>
<A NAME="6654"></A>
<P><A NAME="dingp55"></A>
This problem usually raises its ugly head when you try to improve the efficiency of a function by returning its result by reference instead of <A NAME="p132"></A>by value. The following example is the same as the one in <A HREF="./EC4_FR.HTM#6210" TARGET="_top">Item 23</A>, which pursues in detail the question of when you can return a reference and when you <NOBR>can't:<SCRIPT>create_link(55);</SCRIPT>
</NOBR></P>
<A NAME="18320"></A>
<UL><PRE>class Rational {          // class for rational numbers
public:
  Rational(int numerator = 0, int denominator = 1);
  ~Rational();
</PRE>
</UL><A NAME="18321"></A>
<UL><PRE>  ...
</PRE>
</UL><A NAME="18322"></A>
<UL><PRE>private:
  int n, d;               // numerator and denominator
</PRE>
</UL><A NAME="18323"></A>
<UL><PRE>// notice that operator* (incorrectly) returns a reference
friend const Rational&amp; operator*(const Rational&amp; lhs,
                                 const Rational&amp; rhs);
};
</PRE>
</UL><A NAME="18335"></A>
<UL><PRE>// an incorrect implementation of operator*
inline const Rational&amp; operator*(const Rational&amp; lhs,
                                 const Rational&amp; rhs)
{
  Rational result(lhs.n * rhs.n, lhs.d * rhs.d);
  return result;
}
</PRE>
</UL><A NAME="6665"></A>
<P><A NAME="dingp56"></A>
Here, the local object <CODE>result</CODE> is constructed upon entry into the body of <CODE>operator*</CODE>. However, local objects are automatically destroyed when they go out of scope. <CODE>result</CODE> will go out of scope after execution of the <CODE>return</CODE> statement, so when you write <NOBR>this,<SCRIPT>create_link(56);</SCRIPT>
</NOBR></P>
<A NAME="6667"></A>
<UL><PRE>Rational two = 2;
</PRE>
</UL><A NAME="6668"></A>
<UL><PRE>
Rational four = two * two;         // same as
                                   // operator*(two, two)
</PRE>
</UL><A NAME="6670"></A>
<A NAME="dingp57"></A>what happens during the function call is <NOBR>this:<SCRIPT>create_link(57);</SCRIPT>
</NOBR></P>
<A NAME="6671"></A><OL TYPE="1"><A NAME="dingp58"></A><LI>The local object <CODE>result</CODE> is constructed.<SCRIPT>create_link(58);</SCRIPT>

<A NAME="6673"></A><A NAME="dingp59"></A><LI>A reference is initialized to be another name for <CODE>result</CODE>, and this reference is squirreled away as <CODE>operator*</CODE>'s return value.<SCRIPT>create_link(59);</SCRIPT>

<A NAME="6674"></A><A NAME="dingp60"></A><LI>The local object <CODE>result</CODE> is destroyed, and the space it used to occupy on the stack is made available for use by other parts of the program or by other programs.<SCRIPT>create_link(60);</SCRIPT>

<A NAME="6675"></A><A NAME="dingp61"></A><LI>The object <CODE>four</CODE> is initialized using the reference of step 2.<SCRIPT>create_link(61);</SCRIPT>

</OL></P>
<A NAME="6676"></A>
<P><A NAME="dingp62"></A>
Everything is fine until step 4, at which point there occurs, as they say in the highest of high-tech circles, "a major lossage." The reference initialized in step 2 ceased to refer to a valid object as of the end of step 3, <A NAME="p133"></A>so the outcome of the initialization of object <CODE>four</CODE> is completely <NOBR>undefined.<SCRIPT>create_link(62);</SCRIPT>
</NOBR></P>
<A NAME="6677"></A>
<P><A NAME="dingp63"></A>
The lesson should be clear: don't return a reference to a local <NOBR>object.<SCRIPT>create_link(63);</SCRIPT>
</NOBR></P>
<A NAME="6678"></A>
<P><A NAME="dingp64"></A>
"Okay," you say, "the problem is that the object I want to use goes out of scope too soon. I can fix that. I'll just call <CODE>new</CODE> instead of using a local object." Like <NOBR>this:<SCRIPT>create_link(64);</SCRIPT>
</NOBR></P>
</UL><A NAME="18367"></A>
<UL><PRE>// another incorrect implementation of operator*
inline const Rational&amp; operator*(const Rational&amp; lhs,
                                 const Rational&amp; rhs)
{
  // create a new object on the heap
  Rational *result =
    new Rational(lhs.n * rhs.n, lhs.d * rhs.d);
</PRE>
</UL><A NAME="18368"></A>
<UL><PRE>  // return it
  return *result;
}
</PRE>
</UL><A NAME="6681"></A>
<P><A NAME="dingp65"></A>
This approach does indeed avoid the problem of the previous example, but it introduces a new one in its place. To avoid a memory leak in your software, you know you must ensure that <CODE>delete</CODE> is applied to every pointer conjured up by <CODE>new</CODE>, but ay, there's the rub: who's to make the matching call to <CODE>delete</CODE> for this function's use of <CODE>new</CODE>?<SCRIPT>create_link(65);</SCRIPT>
</P>
<A NAME="6684"></A>
<P><A NAME="dingp66"></A>
Clearly, the <I>caller</I> of <CODE>operator*</CODE> must see to it that <CODE>delete</CODE> is applied. Clear, yes, and even easy to document, but nonetheless the cause is hopeless. There are two reasons for this pessimistic <NOBR>assessment.<SCRIPT>create_link(66);</SCRIPT>
</NOBR></P>
<A NAME="6685"></A>
<P><A NAME="dingp67"></A>
First, it's well-known that programmers, as a breed, are sloppy. That doesn't mean that you're sloppy or that I'm sloppy, but rare is the programmer who doesn't work with someone who is &#151; shall we say? &#151; a little on the flaky side. What are the odds that such programmers &#151; and we all know that they exist &#151; will remember that whenever they call <CODE>operator*</CODE>, they must <I>take the address of the result</I> and then use <CODE>delete</CODE> on it? That is, they must use <CODE>operator*</CODE> like <NOBR>this:<SCRIPT>create_link(67);</SCRIPT>
</NOBR></P>
<A NAME="6686"></A>
<UL><PRE>
const Rational&amp; four = two * two;      // get dereferenced
                                       // pointer; store it in
                                       // a <I>reference</I>
...
</PRE>
</UL><A NAME="6688"></A>

⌨️ 快捷键说明

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