📄 ei30.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> <BR> 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: 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& 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& 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 &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 &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> <BR> 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 + -