zoukankan      html  css  js  c++  java
  • 条款28 :避免返回handles指向对象内部成分

    我们先看一个例子:

    classPoint{

    public:

           Point(intx,inty);

           voidsetX(intnewVal);

           voidsetY(intnewVal);

    };

     

    structRectData{

           Pointulhc;

           Pointlrhc;

    };

    classRectangle{

    public:

           Point&upperLeft()const{returnpData->ulhc;}

           Point&lowerRight()const{returnpData->lrhc;}

           ...

    private:

           std::tr1::shared_ptr<RectData>pData;

    };

    这个Rectangle类中的upperLeft(),lowerRight()这两个方法是返回左上点,和右下点。并不希望客户来修改,所以使用了const关键字来限定。

    但是我们发现这两个函数返回的是pData的内部数据的引用。因此,并没有封装好。也就是说我们可以这样做:

    Pointcoord1(1,1);

    Pointcoord2(100,100);

    constRectanglerec(coord1,coord2);

    rec.upperLeft().setX(50);

    我们还是可以修改的。虽然那个函数是一个const的。所以从这个例子中,我们可以得到以下的教训:

    l  成员变量的封装性会被引用破坏。

    l  如果const成员函数传出一个reference,后者所指的数据与对象自身有关联,而它又被存储于对象之外,那么这个函数的调用者可以修改那笔数据。

    l  同样的,我们返回pointer,Iterator的效果和reference是一样的。

    因此我们可以修改一下:

    classRectangle{

    public:

           constPoint&upperLeft()const{returnpData->ulhc;}

           constPoint&lowerRight()const{returnpData->lrhc;}

           ...

    private:

           std::tr1::shared_ptr<RectData>pData;

    };

    这样就解决了上面的那个问题:也就是说,这些函数让渡了读取权,但是涂写权仍然被禁止。

    但是这样做也不是很好,因为upperLeft和lowerRight还是返回了“代表对象内部“的handles,有可能在其他场合带来问题。更明确的说会导致”dangling handles(空悬的号码牌):这种handles所指的对象不存在了“。考虑下面的例子:

    classGUIObject{};

    constRectangleboundingBox(constGUIObject&obj);

    现在,客户可能这么使用。

    GUIObject*pgo;

    constPoint*pUpperLeft=&(boundingBox(*pgo).upperLeft());

     

    你会发现(boundingBox(*pgo).upperLeft())这是一个point对象。但是当这一句执行完后,这个临时对象会被析构。这时,pUpperLeft会指向一个空的对象。也就出现了悬空现象。

     

    因此,这就是为什么函数如果“返回一个handle代表对象内部成分“总是危险的原因。

    但这并不意味着,绝对不可以让函数返回内部的handles。有时候你必须这样做。比如:

    classFoo{

    public:

           int&operator[](constint);

           constint&operator[](constint)const;

    private:

           vector<int>data;

    }

    int&Foo::operator[](constinti){

           returndata[i];

    }

    constint&Foo::operator[](constinti)const{

           returndata[i]

    }

    请记住:

    • 避免返回handles指向对象的内部。遵守这个条款可增加封装性,帮助const成员函数更加像一个const,并将“虚号码牌“的可能性降低到最低。
  • 相关阅读:
    Java 内部类种类及使用解析
    linux下的一些命令分析与shell的一些命令
    Centos7 安装gitlab
    centos7安装laravel
    laravel中对加载进行优化
    laravel如何利用数据库的形式发送通知
    laravel中的gate
    laravel中的scope作用域
    Laravel 使用firstOrCreate 报错MassAssignmentException
    laravel中关联模型并使用scout导入数据 +视图合成器
  • 原文地址:https://www.cnblogs.com/loveyakamoz/p/2772417.html
Copyright © 2011-2022 走看看