Effective C++ 2e Item30

原创 2001年07月23日 20:23:00

条款30: 避免这样的成员函数:其返回值是指向成员的非const指针或引用,但成员的访问级比这个函数要低

使一个成员为private或protected的原因是想限制对它的访问,对吗?劳累的编译器要费九牛二虎之力来确保你设置的访问限制不被破坏,对不对?所以,写个函数来让用户随意地访问受限的成员没多大意义,对不对?如果你确实认为有意义,那么请反复阅读本段,直到你不这样认为为止。

实际编程中很容易违反这条规则,下面是个例子:

class Address { ... };           // 某人居住在此

class Person {
public:
  Address& personAddress() { return address; }
  ...

private:
  Address address;
  ...
};

成员函数personAddress为调用者提供的是Person对象中所包含的Address对象,但是,也许是出于效率上的考虑,返回结果采用的是引用,而不是值(见条款22)。遗憾的是,这个成员函数的做法有违当初将Person::address声明为private的初衷:

Person scott(...);             // 为简化省略了参数

Address& addr =                // 假设addr为全局变量
  scott.personAddress();

现在,全局对象addr成为了scott.address的另一个名字,利用它可以随意读写scott.address。实际上,scott.address不再为private,而是public,访问级提升的根源在于成员函数personAddress。当然,本例中给出的address 的访问级是private,如果是protected,情况完全一样。

不仅仅是引用,指针也会产生以上问题。下面的例子和上面相同,只不过这次用的是指针:

class Person {
public:
  Address * personAddress() { return &address; }
  ...

private:
  Address address;
  ...
};

Address *addrPtr =
  scott.personAddress();        // 问题和上面一样

而且,对于指针来说,要担心的不仅仅是数据成员,还要考虑到成员函数。因为返回一个成员函数的指针也是有可能的:

class Person;                   // 提前声明

// PPMF = "pointer to Person member function"
// (指向Person成员函数的指针)
typedef void (Person::*PPMF)();

class Person {
public:
  static PPMF verificationFunction()
  { return &Person::verifyAddress; }

  ...

private:
  Address address;

  void verifyAddress();

};

如果你过去没试过象上面那样将成员函数指针和typedef结合起来的用法,可能会觉得Person::verificationFunction的声明有点吓人。别害怕,它的全部含义只不过是:

· verificationFunction是一个没有输入参数的成员函数
· 它的返回值是Person类中一个成员函数的指针
· 被指向的函数(即,verificationFunction的返回值)没有输入参数且没有返回值,即void。

至于static关键字,当它用于对成员的声明时,其含义是:整个类只有这个成员的一份拷贝,并且这个成员可以不通过类的具体对象来访问。有关static的完整介绍可以参考C++教程。(如果你的C++教程里没有介绍静态成员,请把书页撕了扔到垃圾回收站吧。注意封面一定不要乱扔以免破坏环境。最后,去借或买本更好的教程吧。)

最后一个例子中,verifyAddress是一个私有成员函数,这意味着它只是类的一个实现细节,只有类的成员才应该知道它(当然,友员也知道)。但是,由于公有成员函数verificationFunction返回了指向verifyAddress的指针,用户就可以做这样的事:

PPMF pmf = scott.verificationFunction();

(scott.*pmf)();                     // 等同于调用
                                    // scott.verifyAddress

这里,pmf成了Person::verifyAddress的同义词,只是有个重要的区别:可以没有限制地使用它。

虽然前面说了那么多,有一天你可能为了程序的性能还是不得不写象上面那样的函数--------返回值是某个访问级较低的成员的指针或引用。但同时,你又不想牺牲private和protected为你提供的访问限制。这种情况下,你可以通过返回指向const对象的指针或引用来达到两全其美的效果。详细介绍参见条款21。

《Effective C++》学习笔记——条款31

《Effective C++》学习笔记——条款31:将文件间的编译依存关系降至最低
  • lx417147512
  • lx417147512
  • 2015年06月15日 13:51
  • 1368

《Effective C++》让自己习惯C++:条款1-条款4

《Effective C++》条款1到条款4。基本是总结C++的一些特点,尤其是不同于C语言的特点。...
  • KangRoger
  • KangRoger
  • 2014年12月13日 19:26
  • 2352

effective C++ 目录(第三版)

我把目录整理一下,方便在以后工作中查看。 条款01:视C++为一个语言联邦 条款02:尽量以const,enum,inline替换#define 条款03:尽可能使用const 条...
  • u010889616
  • u010889616
  • 2015年12月24日 20:12
  • 519

《Effective C++》读后感

几天前,我曾在微信朋友圈中发了一条消息: 和大牛之间的差距就是这一个书架。 图片来自于微信公众号“二爷鉴书”的分享。 我时常纠结于自己的技术为什么进步的这么慢,大概就是书读的太少、思考的太少。 《E...
  • Since20140504
  • Since20140504
  • 2016年06月27日 12:13
  • 7561

《Effective C++》:条款44-条款45

条款44将与参数无关的代码抽离templates 条款45运用成员函数模板接受所有兼容类型...
  • KangRoger
  • KangRoger
  • 2015年03月12日 22:01
  • 1484

【C++】《Effective C++》读书笔记汇总

我之前边读《Effective C++》边写下每个条款的读书笔记,这一版是C++11之前的版本。这里我将每个条款令我印象深刻的点小结一下。 1、C++包括:Plain C(面向过程)、OOP(面向对...
  • lpsl1882
  • lpsl1882
  • 2016年04月06日 11:14
  • 2258

《Effective C++》学习笔记(六)

原创文章,转载请注明出处:http://blog.csdn.net/sfh366958228/article/details/38922567 前言 今天学的条款都是出自于《设计与声明》这一张,...
  • sfh366958228
  • sfh366958228
  • 2014年08月29日 20:00
  • 746

《Effective C++》:条款41-条款42

条款41了解隐式接口和编译期多态 条款42了解typename的双重意义条款
  • KangRoger
  • KangRoger
  • 2015年03月10日 22:13
  • 1204

《Effective C++》:条款28-条款29

条款28避免返回handles指向对象内部成分:指的是不能返回对象内部数据/函数的引用、指针等。 条款29为异常安全而努力是值得的:指的是要有异常处理机制,避免发生异常时造成资源泄露等问题。...
  • KangRoger
  • KangRoger
  • 2015年02月19日 19:47
  • 1372

《Effective C++》资源管理:条款13-条款15

在系统中,资源是有限的,一旦用完必须归还给系统,否则可能会造成资源耗尽或其他问题。例如,动态分配的内存如果用完不释放会造成内存泄漏。 这里说的资源不仅仅是指内存,还包括其他,例如文件描述符、网络连接、...
  • KangRoger
  • KangRoger
  • 2015年01月14日 21:46
  • 1285
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Effective C++ 2e Item30
举报原因:
原因补充:

(最多只允许输入30个字)