条款28:避免返回handles指向对象的内部成分。

首先看看下面这个例子:

 1 class Point{
 2 public:
 3     point(int x, int y);
 4     ...
 5     void setX(int newVal);
 6     void setY(int newVal);
 7     ...
 8 };
 9 struct RectData{
10     Point ulhc; //左上角
11     Point lrhc; //右下角
12 };
13 class Rectangle{
14     ...
15 private:
16     shared_ptr<RectData> pData;
17 };

那么如果出现下面这种成员函数的话:

1 class Rectangle{
2 public:
3     ...
4     Point & upperLeft() const {return pData->ulhc; }
5     Point & lowerRight() const{return pData->lrhc; }
6     ...
7 }
这样只是能通过编译,但是设计确是错误的,在成员函数被声明为const的情况下返回了一个内部成员的引用,这样使得ulhc 以及 lrhc对象都可以被更改。但是二者都是private的,实际上二者都是不应该被改变的。
这正是由于返回的是引用,同样的返回指针,迭代其这种叫做handle的对象都是会造成内部状态暴露在外面。
这些问题实际上在每个方法的返回的handle上加上const就会得到解决。
1 class Rectangle{
2 public:
3     ...
4     const Point & upperLeft() const {return pData->ulhc; }
5     const Point & lowerRight() const{return pData->lrhc; }
6     ...
7 }

但是几十这样做仍然可能会导致造成虚调handle的现象发生:

class GUIobject{...};
const Rectangle
    boundingBox(const GUIobject & obj);
//那么,当用户这样去使用他的时候
GUIobject * pgo;
...
const Point * pUpperLeft = 
    &(boundingBox(*pgo).pUpperLeft());
这样实际上将Rectancle中的Point对象传递出去了,这样当临时对象析构的时候,这个指针就会编程一个空悬的指针(感觉通过智能指针就能解决啊),这样也带来了风险。
 
小结:
避免返回Handle指向内部对象,这样可以增加封装性,帮助const函数的行为像是一个const,并将空悬Handle的可能性降到最低。
原文地址:https://www.cnblogs.com/-wang-cheng/p/4872324.html