Item 23: 멤버 함수보다는 비멤버 비프렌드 함수와 더 가까워지자
class WebBrowser {
public:
...
void clearCache();
void clearHistory();
void removeCookies();
...
};
1. 이 세 동작을 한 번에 해주는 함수를 만든다면 멤버 함수로 해야 할까? 아니면 비멤버 함수로 해야 할까?
즉
class WebBrowser {
public:
...
void clearEverything();
...
};
이 코드가 더 좋을까? 아니면
void clearBrower(WebBrower& wb);
{
wb.clearCache();
wb.clearHistory();
wb.removeCookies();
}
이 코드가 더 좋을까?
비멤버 비프렌드 함수가 더 좋다.
- 캡슐화면에서 더 좋다.
- 패키징 유연성 제공
- 컴파일 의존도를 낮추고 WebBrowser의 확장성도 높일 수 있다.
2. 캡슐화의 좋은 점은?
어떤 것을 캡슐화하면 외부에서 이것을 볼 수 없게 된다. 캡슐화하는 것이 늘면 그 만큼 밖에서 볼 수 있는 것들이 줄어든다. 밖에서 볼 수 있는 것이 줄어들면, 그것을 바꿀 때 필요한 유연성이 커진다. 왜냐하면 변경 자체가 줄 수 있는 범위가 줄어들기 때문이다. 이것이 캡슐화의 최대 장점이다.
- 멤버함수보다 비멤버 비프렌드 함수가 캡슐화에 더 유리한 이유는?
private 멤버는 멤버 함수 및 프렌드 함수만 접근할 수 있다. 캡슐화가 높다는 말은 데이터들을 접근할 수 있는 것들이 적다는 말이다. 그런데 비멤버 비프렌드 함수도 할 수 있는 일을 멤버함수로 만들게 되면 오히려 private 데이터에 접근할 수 있는 채널이 많아지게 된다. 즉 캡슐화가 떨어진다.
4. 이 말의 주의점은?
- 멤버함수와 비멤버 비프렌드 함수 사이의 선택이다. 그냥 비멤버가 아니다.
- 어떤 함수는 어떤 클래스의 비멤버가 되어야 한다는 말은 이 함수가 다른 클래스의 멤버함수가 될 수 없다는 뜻이 아니다.
즉 clearBrowser 함수가 다른 유틸리티 클래스의 정적 멤버함수로 만들어도 된다. 중요한 것은 이 함수가 WebBrowser 클래스의 멤버함수(혹은 프렌드)가 아니기만 하면된다.
5. C++에서 위 두번째 방식을 구현하는 좋은 방법은?
어떤 네임스페이스 안에 구현하는 것이다.
namespace WebBrowserStuff {
class WebBrowser { ... };
void clearBrowser(WebBrowser& wb);
...
}
네임스페이스의 장점은?
클래스와 달리 여러개의 파일에 나누어 만들 수 있다.
예를 들어 WebBrowser 클래스처럼 응용도가 높은 클래스는 편의 함수가 많이 존재할 수 있는데 이런 경우 각각의 성격에 맞는 파일들을 새로 만들고 이 파일들에서 같은 이름의 네임스페이스를 선언해서 만들면된다.
// "webBrower.h" 헤더 --- WebBrower 클래스 자체에 대한 헤더
namespace WebBrowerStuff {
class WebBrowser{ ... };
...
}
// "webbrowerbookmarks.h" 헤더
namespace WebBrowserStuff {
... // 즐겨찾기 관련 편의 함수
}
// "webbrowsercookies.h" 헤더
namespace WebBrowserStuff {
... // 쿠키 관련 편의 함수
}
표준 C++ 라이브러리가 이러한 구조로 동작한다. std 네임스페이스에 속한 모든 것들이 한 파일에 있는 것이 아니고 기능과 관련된 함수들이 수십 개의 헤더(<vector>, <algorithm>, <memory> 등) 에 흩어져 선언되어 있다.
- 편의 함수를 여러 개의 파일에, 그러나 하나의 네임스페이스에, 나누어 두면 확장성이 쉬어진다.
해당 네임스페이스 비멤버 비프렌드 함수를 넣으면 된다.
정리
- 멤버 함수보다는 비멤버 비프렌드 함수를 자주 쓰도록 하자. 캡슐화 정도가 높아지고, 패키징 유연성도 커지며, 기능적인 확장성도 늘어난다.