EffectiveC++读书笔记——item28(避免返回对象内部构件的“句柄”)

1. 矩形案例引出的问题

在矩形应用程序中,Rectangle类为保持较小状态,将表示矩形两角点的Point数据放在辅助结构体RectData中,通过智能指针pData指向。为方便客户操作矩形区域,提供upperLeftlowerRight函数返回内部Point对象的引用:

class Point {
public:
    Point(int x, int y);
    void setX(int newVal);
    void setY(int newVal);
};

struct RectData {
    Point ulhc;
    Point lrhc;
};

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

此设计虽能编译,但存在矛盾。upperLeftlowerRight声明为const成员函数,本意是不允许客户改变Rectangle对象,然而它们返回的内部数据引用却使客户能修改内部数据,破坏了对象的const特性。例如:

Point coord1(0, 0);
Point coord2(100, 100);
const Rectangle rec(coord1, coord2);
rec.upperLeft().setX(50); 

这里,rec本应是const矩形,却因返回的引用被修改。同时,这也揭示了数据成员虽被封装,但通过公共函数返回内部引用,实际上将内部数据公开了。

2. 句柄的风险及涵盖范围

引用、指针和迭代器都属于 “句柄”。返回对象内部构件的句柄不仅会危及对象封装安全,还可能导致const成员函数改变对象状态。不仅数据成员,protectedprivate的成员函数也属于对象内部构件,同样不应返回指向它们的句柄,否则会提升其访问级别。例如,若有成员函数返回指向private成员函数的指针,客户就能通过该指针调用此private函数。

3. 改进设计及遗留问题

upperLeftlowerRight函数的返回类型改为const Point&,可解决上述问题,使客户只能读取矩形的点,不能修改,增强了const成员函数的有效性,同时这也是对封装的有限放松:

class Rectangle {
public:
    const Point& upperLeft() const { return pData->ulhc; }
    const Point& lowerRight() const { return pData->lrhc; }
};

但即便如此,返回内部构件句柄仍存在风险,如可能产生空悬句柄。以获取 GUI 对象边界框函数为例:

class GUIObject {};
const Rectangle boundingBox(const GUIObject& obj);

GUIObject *pgo; 
const Point *pUpperLeft = &(boundingBox(*pgo).upperLeft()); 

boundingBox返回的临时Rectangle对象(设为temp)在语句结束时被销毁,其内部Point对象也随之析构,导致pUpperLeft成为空悬指针,指向已不存在的对象。

4. 总结与建议

虽然在某些特殊情况下(如stringvectoroperator[])需要返回句柄,但一般应避免返回对象内部构件的句柄(引用、指针或迭代器)。这样做有助于提高对象封装性,确保const成员函数真正发挥const效果,并最大程度降低空悬句柄产生的可能性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值