定义下面的类和结构:
1 class Point 2 { 3 public: 4 Point(int x, int y); 5 ... 6 void setX(int newVal); 7 void setY(int newVal); 8 }; 9 struct RectData 10 { 11 Point ulhc; 12 Point lrhc; 13 }; 14 class Rectangle 15 { 16 ... 17 private: 18 std::tr1::shared_ptr<RectData> pData; 19 };
那么下面的成员变量是否有不合理的地方:
1 class Rectange 2 { 3 public: 4 Point& upperLeft() { return pData->ulhc; } 5 Point& lowerRight() { return pData->lrhc; } 6 ... 7 };
上面不合理的地方在第4和第5行,const成员变量的本意是只返回数据,但不允许修改对象内部的数据,但是上面的代码由于返回了指向对象内部变量的handle,破坏了封装性,因为用户可以通过这个handle来修改Point的属性。为了解决这个问题,可以令这个handle为const,这样就不可修改,即:
1 const Point& upperLeft() { return pData->ulhc; } 2 const Point& lowerRight() { return pData->lrhc; }
即使如此,返回指向对象内部的handle还可能带来其他的问题,比如返回一个空的handle,例如下面的代码:
1 class GUIObject { ... }; 2 const Rectangle boundingBox(const GUIObject& obj); 3 4 GUIObject* pgo; 5 ... 6 const Point* pUpperLeft = &(boundingBox(*pgo).upperLeft));
第6行Point指向boundingBox(*pgo)获得的一个临时对象的一个内部成员,但是由于boundingBox(*pgo)返回对象在语句6执行结束后就会被析构,从而导致其内部成员变量Point对象也会被析构,因而pUpperLeft将指向一个空的对象,即变成空悬、虚吊即dangling的handle。
当然,并不是所有的成员函数都不该返回handle,例如operator[],它需要返回指向容器内部数据的handle。
综上,在定义类的过程中,应避免返回handle指向对象内部成分,这样可以增加封装性,使得const成员函数执行起来真正具有const的性质,并避免得到虚吊的handle。
以上整理自Effective C++中文版第三版case 28.