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

📄 9029.htm

📁 C++细节解释
💻 HTM
字号:
<HTML>
<HEAD>
<meta http-equiv='Content-Type' content='text/html; charset=gb2312'>


<style >
.fst{padding:0px 15px;width:770px;border-left:0px solid #000000;border-right:0px solid #000000}
.fstdiv3 img{border:0px;border-right:8px solid #eeeecc;border-top:6px solid #eeeecc}
</style>
<title>
Effective C++ 2e Item30
</title>
</HEAD>
<BODY >
<center>

<div align=center><div class=fst align=left><div class=fstdiv3 id=print2>
<b>
Effective C++ 2e Item30&nbsp;</b><p>条款30: 避免这样的成员函数:其返回值是指向成员的非const指针或引用,但成员的访问级比这个函数要低</p> 
<p>使一个成员为private或protected的原因是想限制对它的访问,对吗?劳累的编译器要费九牛二虎之力来确保你设置的访问限制不被破坏,对不对?所以,写个函数来让用户随意地访问受限的成员没多大意义,对不对?如果你确实认为有意义,那么请反复阅读本段,直到你不这样认为为止。</p> 
<p>实际编程中很容易违反这条规则,下面是个例子:</p> 
<p>class address { ... };&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 某人居住在此</p> 
<p>class person {<br>public:<br>&nbsp; address&amp; personaddress() { return address; }<br>&nbsp; ...</p> 
<p>private:<br>&nbsp; address address;<br>&nbsp; ...<br>};</p> 
<p>成员函数personaddress为调用者提供的是person对象中所包含的address对象,但是,也许是出于效率上的考虑,返回结果采用的是引用,而不是值(见条款22)。遗憾的是,这个成员函数的做法有违当初将person::address声明为private的初衷:</p> 
<p>person scott(...);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 为简化省略了参数</p> 
<p>address&amp; addr =&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 假设addr为全局变量<br>&nbsp; scott.personaddress();</p> 
<p>现在,全局对象addr成为了scott.address的另一个名字,利用它可以随意读写scott.address。实际上,scott.address不再为private,而是public,访问级提升的根源在于成员函数personaddress。当然,本例中给出的address 的访问级是private,如果是protected,情况完全一样。</p> 
<p>不仅仅是引用,指针也会产生以上问题。下面的例子和上面相同,只不过这次用的是指针:</p> 
<p>class person {<br>public:<br>&nbsp; address * personaddress() { return &amp;address; }<br>&nbsp; ...</p> 
<p>private:<br>&nbsp; address address;<br>&nbsp; ...<br>};</p> 
<p>address *addrptr =<br>&nbsp; scott.personaddress();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 问题和上面一样</p> 
<p>而且,对于指针来说,要担心的不仅仅是数据成员,还要考虑到成员函数。因为返回一个成员函数的指针也是有可能的:</p> 
<p>class person;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 提前声明</p> 
<p>// ppmf = "pointer to person member function"<br>// (指向person成员函数的指针)<br>typedef void (person::*ppmf)();</p> 
<p>class person {<br>public:<br>&nbsp; static ppmf verificationfunction()<br>&nbsp; { return &amp;person::verifyaddress; }</p> 
<p>&nbsp; ...</p> 
<p>private:<br>&nbsp; address address;</p> 
<p>&nbsp; void verifyaddress();</p> 
<p>};</p> 
<p>如果你过去没试过象上面那样将成员函数指针和typedef结合起来的用法,可能会觉得person::verificationfunction的声明有点吓人。别害怕,它的全部含义只不过是:</p> 
<p>· verificationfunction是一个没有输入参数的成员函数<br>· 它的返回值是person类中一个成员函数的指针<br>· 被指向的函数(即,verificationfunction的返回值)没有输入参数且没有返回值,即void。</p> 
<p>至于static关键字,当它用于对成员的声明时,其含义是:整个类只有这个成员的一份拷贝,并且这个成员可以不通过类的具体对象来访问。有关static的完整介绍可以参考c++教程。(如果你的c++教程里没有介绍静态成员,请把书页撕了扔到垃圾回收站吧。注意封面一定不要乱扔以免破坏环境。最后,去借或买本更好的教程吧。)</p> 
<p>最后一个例子中,verifyaddress是一个私有成员函数,这意味着它只是类的一个实现细节,只有类的成员才应该知道它(当然,友员也知道)。但是,由于公有成员函数verificationfunction返回了指向verifyaddress的指针,用户就可以做这样的事:</p> 
<p>ppmf pmf = scott.verificationfunction();</p> 
<p>(scott.*pmf)();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 等同于调用<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // scott.verifyaddress</p> 
<p>这里,pmf成了person::verifyaddress的同义词,只是有个重要的区别:可以没有限制地使用它。</p> 
<p>虽然前面说了那么多,有一天你可能为了程序的性能还是不得不写象上面那样的函数--------返回值是某个访问级较低的成员的指针或引用。但同时,你又不想牺牲private和protected为你提供的访问限制。这种情况下,你可以通过返回指向const对象的指针或引用来达到两全其美的效果。详细介绍参见条款21。</p> 
</DIV></div></div> 
 
</center></BODY></HTML> 

⌨️ 快捷键说明

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