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

条款28:避免返回handles指向对象内部成分
    (Avoid returning "handles" to object internals.)

内容:
    这里所谓的handles一般包括内部对象的references、pointer、iterator,这条款是如何产生的呢?理由是什么
呢?我先不必急着回答你这些问题,我们先来看一个例子,假设我们的程序中要用到矩形,于是我们写了Rectangle类去
描述它,该类的内部对象为矩形左上角(upper left-hand corner)、右下角(Lower right-hand corner)两个Point
对象,为了得到这两个内部对象数据我们提供了upperLeft与lowerRight函数接口.由于这里Point类是自定义类型,故
我们先开始定义该类:
    class Point{
    public:   
        Point(int x,int y); 
        ...
        void setX(int value);
        void setY(int value);
        ...
    };
    接下来我们开始写Rectangle类,考虑到让该类尽可能的小,我决定不把Point点定义在类的内部,而是通过在其内部
放一个辅助类对象指针,该辅助类中存放两个Point对象.这种做法很常见,下面我们来实现:
    struct RectData{
        Point upperLeftPoint,lowerRightPoint;       
    };
    class Rectangle{
    public:
        ...
        Point& upperLeft()const{ //返回内部对象数据handle
            return pData->upperLeftPoint;
        }
        Point& lowerRight()const{ //返回内部对象数据handle
            return pData->lowerRightPoint;
        }
    private:
        std::tr1::shared_ptr<RectData> pData;
    };
    一看代码我们就会很轻易的发现这里存在一个安全隐患:该类提供的两个接口返回的私有区域内部对象,那么客户
使用该类的时候,有可能修改了该内部对象的数据,而实际上我们是不想让客户拥有这个权限的.例如:
    Point coord1(0,0);
    Point coord2(100,100);
    const Rectangle rec(coord1,coord2);
    rec.upperLeft().setX(50);//wow, it changes the internal data,that's amazing!
    从这个例子我们至少可以了解以下两点:(1)返回内部对象相当于让内部对象变为对用户可见即相当于让其处于
public区段中;(2)客户可以通过返回内部对象handle接口函数修改private对象属性,这显然不是我们想要的结果
.怎么解决?其中的一个解决方案就是在返回类型上加上const即可:
    class Rectangle{
    public:
        ...
        const Point& upperLeft()const{return pData->upperLeftPoint;}
        const Point& lowerRight()const{return pData->lowerRightPoint;}
        ...
    };
    问题似乎得到了解决,我们愿意让客户看到Rectangle的外围Points,所以这里是蓄意放松封装.更重要的是这是
一个有限度的放松:这些函数只让出读取权,而修改权限仍然是被禁止的.在你说这个解决方案完全perfect之前,这时
客户默默的写下了下面这段"恐怖"的代码:
    class GUIObject{...};//GUI base  class
    const Rectangle boundingBox(const GUIObject& obj);//该函数返回GUI对象的外框.
    现在客户有可能这么用这个函数:
    GUIObject* pObject = NULL;
    ... //create GUIObject object
    const Point* pUpperLeft = &( boudingBox(*pObject).upperLeft());
    喔欧,看出问题了没有?boudingBox返回了一个临时对象对象(姑且称之为tempt),upperLeft返回的是tempt
对象的内部数据的引用,那么现在pUpperLeft就指向该tempt对象的内部对象的地址.这里你别忘记啰:该语句调用
结束以后tempt对象自动销毁,此时的pUpperLeft指向的就是一个不存在的对象.pUpperLeft也就是变成空悬、
悬挂了(dangling)!呵呵.
    今天我们就讨论到这里,如有什么问题的话,请留言.
    请记住:
    ■ 避免返回handles(包括reference,pointer,iterator)指向内部对象.遵守这个条款可增加封装性,帮助const
成员函数的行为像个const,并将发生"虚吊号码牌"(dangling handles)的可能性降至最低.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值