class Point
{
public:
Point(int x, int y);
...
void setX(int newVal);
void setY(int newVal);
...
};
struct RectData
{
Point ulhc; // upper left-hand corner (좌측 상단)
Point ulhc; // lower right-hand corner (우측 하단)
};
// 사각형 클래스
class Rectangle
{
publc:
...
Point& upperLeft() const { return pData->ulhc; }
Point& lowerRight() const { return pData->lrhc; }
...
private:
shared_ptr<RectData> pData;
};
여기서 upperLeft
, lowerRight
함수는 상수 함수인데 pData
객체에 대한 참조자를 반환하고 있다.
Point coord1(0, 0);
Point coord2(100, 100);
const Rectangle rec(coord1, coord2);
rec.upperLeft().setX(50); // upperLeft가 (0, 0)이 아니라 (50, 0)이 된다..!
따라서 upperLeft
, lowerRight
의 리턴값을 통해 Rectangle
객체의 내부 데이터가 수정될 수 있다.
즉, 내부 요소에 대한 핸들(참조자, 포인터, 반복자)을 반환하는 함수는 그 객체의 캡슐화를 무너뜨린다.
(여기서 내부 요소에는 함수도 포함이다.)
const Point& upperLeft() const { return pData->ulhc; }
const Point& lowerRight() const { return pData->lrhc; }
반환 타입에 const
를 붙이면 상수 함수에 걸맞게, 함수의 호출부에서 객체의 상태를 바꿀 수 없다.
class GUIObject { ... };
const Rectangle boundingBox(const GUIObject* obj);
...
GUIObject *pgo;
...
const Point *pUpperLeft = &(boudingBox(*pgo).upperLeft());
boudingBox(*pgo)
로 Rectangle
임시 객체(temp
)가 생성된다.temp
에 대해 upperLeft
를 호출하면 Point
객체 참조자가 반환된다.temp
가 소멸되므로 Point
객체들도 사라진다.즉, pUpperLeft
가 가리키는 객체는 사라진다!
이 무효 참조 핸들 문제는 핸들의 종류, 핸들에 const가 붙었는지 여부에 상관없이 핸들을 반환하는 함수라면 발생한다.
정리
- 어떤 객체의 내부 요소에 대한 핸들(참조자, 포인터, 반복자)을 반환하는 것을 되도록 피하자.
- 핸들 반환 함수가 적을수록
- 캡슐화 ↑
- 상수 멤버 함수가 객체의 상수성을 유지
- 무효 참조 핸들 문제를 최소화