Effective C++读书笔记:条款28

Aki 发布于 2022-09-25 250 次阅读


28避免返回handles指向对象内部部分:

1、什么是handles?函数返回handles有什么危害?

reference、指针、迭代器系统都是所谓的handles(号码牌,用来获得某个对象)。函数返回一个handle,随之而来的便是“减低对象封装性”的风险。它也可能导致:虽调用const成员函数却造成对象状态被更改的风险。

class Point
{
public:
       Point(int x,int y);
       voidsetX(int newVal);
       voidsetY(int newVal);
};

struct RectData
{
       Point ulhc;
       Point lrhc;
};

class Rectangle
{
public:
       Point& upperLeft()const{return pData->ulhc;}
       Point& lowerRight()const{return pData->lrhc;}
       ...
private:
       std::shared_ptr<RectData>pData;
};

上述代码便是自相矛盾的一个例子。point 类是一个代表点的类,RectData代表一个矩形的结构,Rectangle类则代表一个矩形,该类能够返回表示矩阵的左上和右下的两个点。由于这两个函数为const的,因此所要表达的意思就是,返回矩阵的两个点,但是不能修改他们。但是又由于返回的是点的reference形式,因此通过reference,实际是可以改变返回的点的数据的。因此,造成了自相矛盾。问题的原因就是,函数返回了handle。

2、上述矛盾带来的启示

  • 成员变量的封装性最多等于“返回其reference”的函数的访问级别。即使数据本身被声明为private的,但是如果返回他们的reference是public的,那么数据的访问权限就编程public了。
  • 如果const成员函数传出一个reference,后者所指数据又不在自身对象内,那么这个函数的调用者可以修改此数据。(这是 bitwise constness 带来的后果。)

3、改进版 返回const handles 指向对象内部成分 可能带来的问题:解决了自相矛盾,却可能形成虚吊问题

(1)上述代码的改进版本:在返回handles 的成员函数前加const。这便解决了自相矛盾问题。

4、最终的结论

无论返回的handle是指针、reference、或者迭代器,也无论他是否为const。只要一个handle被传出去了,都是比较危险的。

5、本条款的例外情况

有时候必须返回handle,例如operator[],operator=。然而这只是少数的例外。

6. 请记住

避免返回handles(包括references,指针,迭代器)指向对象的内部。遵守这个条款可增加封装性,帮助const成员函数行为像个const,并将发生”虚吊号码牌“的可能性降到最低。