• Effective C++:条款28:避免返回 handles 指向对象内部成员


    (一)

    有时候为了让一个对象尽量小,能够把数据放在另外一个辅助的struct中,然后再让一个类去指向它。看以下的代码:

    class Point {
    public:
    	Point(int x, int y);
    	void setX(int newVal);
    	void setY(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::tr1::shared_ptr<RcetData> pData;
    };
    这种设计看上去非常beautiful。可是却是错误的,实际上它是自相矛盾的,看以下的代码:

    Point coord1(0, 0);
    Point coord2(100, 100);
    const Rectangle rec(coord1, coord2);
    rec.upperleft().setX(50);
    错误的理由:(1)upperLeft()跟lowerRight()这两个函数都是const的,所以客户不能改动Rectangle;

    (2)两个函数都返回reference指向private内部数据,调用者于是可通过这些reference更改内部数据。

    upperLeft的调用者可以使用被返回的引用来更改成员。但rec事实上应该是不可变的(const)!

    所以上面那种类的设计是错误的!!!

    所以从这个样例中,我们能够得到下面的教训:

    (1)成员变量的封装性会被引用破坏。

    (2)假设const成员函数传出一个reference,后者所指的数据与对象自身有关联,而它又被存储于对象之外,那么这个函数的调用者能够改动那笔数据。

    相同的道理,返回对象的引用、指针、迭代器都会造成这样的局面,它们都是“句柄”。返回一个代表对象内部数据的句柄,会减少对象的封装。


    (二)解决的方法:

    仅仅要对这两个函数的返回类型加上const就可以:

    class Rectangle {
    public:
    	const Point& upperLeft() const { return pData->ulhc; }
    	const Point& lowerRight() const { return pData->lrhc; }
    private:
    	std::tr1::shared_ptr<RcetData> pData;
    };
    有了这种改变,客户就仅仅能读取矩形的Points,可是不能涂写它们。

    (三)

    上面那种解决方法尽管确保了内部对象不会被改动。可是却可能导致dangling handles(空悬的号码牌):这样的handles所指东西(的所属对象)不复存在。

    这样的“不复存在的对象”最常见的来源就是函数返回值。

    class GUIObject {...};
    const Rectangle boundingBox(const GUIObject& obj);
    
    GUIObject* pgo;
    const Point* pUpperLeft = &(boundingBox(*pgo).upperLeft());
    
    你会发现(boundingBox(*pgo).upperLeft())这是一个point对象。可是当这一句运行完后,这个暂时对象temp会被析构。这时,pUpperLeft会指向一个空的对象。也就出现了悬空现象。

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


    请记住:

    (1)避免返回handles指向对象的内部。遵守这个条款可添加封装性,帮助const成员函数更加像一个const,并将“虚号码牌“的可能性减少到最低。







  • 相关阅读:
    再战设计模式(九)之组合模式
    再战设计模式(八)之桥接模式
    再战设计模式(七)之代理模式
    nyoj 题目2 括号配对问题
    剑指offer 面试题38
    杭电 1005
    九度oj 题目1552:座位问题
    九度oj 题目1482:玛雅人的密码 清华大学机试
    九度oj 题目1496:数列区间
    九度oj 题目1495:关键点
  • 原文地址:https://www.cnblogs.com/yxwkf/p/4543495.html
Copyright © 2020-2023  润新知