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

📄 ei30.htm

📁 一个非常适合初学者入门的有关c++的文档
💻 HTM
字号:
<!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 30: Avoid member functions that return non-const pointers or references to members less accessible than themselves</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 = "EI30_DIR.HTM";

var dingtext = "Item 30, P";

if (self == top) {

 top.location.replace(dingbase + this.location.hash);

}

</SCRIPT>

</HEAD>

<BODY BGCOLOR="#FFFFFF" TEXT="#000000" ONLOAD="setResize()">
<!-- SectionName="E30: Avoid ptr/ref returns that violate constness" -->

<A NAME="6599"></A>
<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./EI29_FR.HTM" TARGET="_top">Item 29: Avoid returning "handles" to internal data.</A> &nbsp;&nbsp;<BR>&nbsp;&nbsp;Continue to <A HREF="./EI31_FR.HTM" TARGET="_top">Item 31:  Never return a reference to a local object or to a dereferenced pointer initialized by new within the function. </A></FONT></DIV>

<A NAME="dingp1"></A></P><A NAME="p129"></A><FONT ID="eititle">Item 30: &nbsp;Avoid member functions that return non-<CODE>const</CODE> pointers or references to members less accessible than themselves.</FONT><SCRIPT>create_link(1);</SCRIPT>

</P>

<A NAME="6600"></A>

<A NAME="dingp2"></A></P>

The reason for making a member private or protected is to limit access to it, right? Your overworked, underpaid C++ compilers go to lots of trouble to make sure that your access restrictions aren't circumvented, right? So it doesn't make a lot of sense for you to write functions that give random clients the ability to freely access restricted members, now, does it? If you think it <I>does</I> make sense, please reread this paragraph over and over until you agree that it doesn't.

<SCRIPT>create_link(2);</SCRIPT>

</P>

<A NAME="6601"></A>

<A NAME="dingp3"></A></P>

It's easy to violate this simple rule. Here's an example:

<SCRIPT>create_link(3);</SCRIPT>

</P>

<A NAME="6603"></A>

<UL><PRE>class Address { ... };           // where someone lives

</PRE>
</UL><A NAME="6606"></A>

<UL><PRE>class Person {

public:

  Address&amp; personAddress() { return address; }

  ...

</PRE>
</UL><A NAME="18280"></A>

<UL><PRE>private:

  Address address;

  ...

};

</PRE>
</UL><A NAME="6610"></A>

<A NAME="dingp4"></A></P>

The member function <CODE>personAddress</CODE> provides the caller with the <CODE>Address</CODE> object contained in the <CODE>Person</CODE> object, but, probably due to efficiency considerations, the result is returned by reference instead of by value (see <A HREF="./EI22_FR.HTM#6133" TARGET="_top">Item 22</A>). Unfortunately, the presence of this member function defeats the purpose of making <CODE>Person::address</CODE> private:

<SCRIPT>create_link(4);</SCRIPT>

</P>

<A NAME="6614"></A>

<UL><PRE>

Person scott(...);             // parameters omitted for

                               // simplicity

</PRE>
</UL><A NAME="6615"></A>

<UL><PRE>

Address&amp; addr =                // assume that addr is

  scott.personAddress();       // global

</PRE>
</UL><A NAME="6616"></A>

<A NAME="dingp5"></A></P>

Now the global object <CODE>addr</CODE> is <I>another name</I> for <CODE>scott.address</CODE>, and it can be used to read and write <CODE>scott.address</CODE> at will. For all practical purposes, <CODE>scott.address</CODE> is no longer private; it is public, and the source of this promotion in accessibility is the member function <CODE>personAddress</CODE>. Of course, there is nothing special about the access level <CODE>private</CODE> in this example; if <CODE>address</CODE> were protected, exactly the same reasoning would apply.

<SCRIPT>create_link(5);</SCRIPT>

</P>

<A NAME="6617"></A>

<A NAME="dingp6"></A></P>

References aren't the only cause for concern. Pointers can play this game, too. Here's the same example, but using pointers this time:

<SCRIPT>create_link(6);</SCRIPT>

</P>

<A NAME="6619"></A>

<UL><PRE><A NAME="p130"></A>class Person {

public:

  Address * personAddress() { return &amp;address; }

  ...

</PRE>
</UL><A NAME="18291"></A>

<UL><PRE>private:

  Address address;

  ...

};

</PRE>
</UL><A NAME="6623"></A>

<UL><PRE>Address *addrPtr =

  scott.personAddress();        // same problem as above

</PRE>
</UL><A NAME="6624"></A>

<A NAME="dingp7"></A></P>

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 function:

<SCRIPT>create_link(7);</SCRIPT>

</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="dingp8"></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 is<SCRIPT>create_link(8);</SCRIPT>

<UL><A NAME="6636"></A>

<A NAME="dingp9"></A><LI><CODE>verificationFunction</CODE> is a member function that takes no parameters;<SCRIPT>create_link(9);</SCRIPT>

<A NAME="6637"></A>

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

<A NAME="6638"></A>

<A NAME="dingp11"></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(11);</SCRIPT>

</UL></P>

<A NAME="6640"></A>

<A NAME="dingp12"></A></P>

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 textbook.)

<SCRIPT>create_link(12);</SCRIPT>

</P>

<A NAME="222559"></A>

<A NAME="dingp13"></A></P>

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 thing:

<SCRIPT>create_link(13);</SCRIPT>

</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>

<A NAME="dingp14"></A></P>

Here, <CODE>pmf</CODE> has become a synonym for <CODE>Person::verifyAddress</CODE>, with the crucial difference that there are no restrictions on its use.

<SCRIPT>create_link(14);</SCRIPT>

</P>

<A NAME="6645"></A>

<A NAME="dingp15"></A></P>

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="./EI21_FR.HTM#6003" TARGET="_top">Item 21</A>.

<SCRIPT>create_link(15);</SCRIPT>

</P>

<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./EI29_FR.HTM" TARGET="_top">Item 29: Avoid returning "handles" to internal data.</A> &nbsp;&nbsp;<BR>&nbsp;&nbsp;Continue to <A HREF="./EI31_FR.HTM" TARGET="_top">Item 31:  Never return a reference to a local object or to a dereferenced pointer initialized by new within the function. </A></FONT></DIV>

</BODY>

</HTML>

⌨️ 快捷键说明

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