[Effective C++] 23. 멤버 함수보다는 비멤버 비프렌드 함수와 더 가까워지자
캡슐화의 의미
어떤 것을 캡슐화하면, 우선 외부에서 이것을 볼 수 없게 된다. 그리고 캡슐화한 것들이 늘어나면 그만큼 밖에서 볼 수 있는 것들이 줄어드므로 다른 것들을 바꿀 때 필요한 유연성이 커진다.
즉, 해당 객체의 데이터에 접근할 수 있는 함수가 많을수록 캡슐화 정도는 낮다.
멤버 함수 vs 비멤버, 비프랜드 함수
class WebBrowser
{
public:
void clearCache();
void clearHistory();
void removeCokies();
};
// 멤버 함수 - 한번에 처리
class WebBrowser(){
public:
void clearEveryThing();
};
// 비멤버 함수
void clearBrowser(WebBrowser& wb)
{
wb.clearCache();
wb.clearHistory();
wb.removeCookies();
}
위의 코드에서 멤버 함수가 비멤버 함수 중 어떤 쪽이 더 캡슐화가 잘 되어 있을까? 바로 비멤버 함수이다.
비멤버 함수가 왜 더 캡슐화가 잘 되어 있는지 알아보기 전에 비멤버 함수가 가져다주는 특성들을 살펴보자.
- 패키징 유연성
- 컴파일 의존도 감소
- 더 나은 확장성 제공
앞서 말한 것처럼 캡슐화는 이미 있는 코드를 바꾸더라도 제한된 사용자들 밖에 영향을 주지 않는 융통성을 확보할 수 있는 수단이다.
즉, 멤버 변수에 접근할 수 있는 함수의 개수가 적을수록 캡슐화가 잘 되어 있다. 그리고 비멤버 비프랜드 함수는 어떤 클래스의 private 멤버 부분을 접근할 수 있는 함수의 개수를 늘리지 않기 때문에 멤버 함수보다 캡슐화가 더 잘되어 있다.
하지만 '함수는 어떤 클래스의 비멤버가 되어야 한다'는 주장이 '그 함수는 다른 클래스의 멤버가 될 수 없다'는 의미는 아니라는 것을 주의해야 한다.
그리고 C++에서는 이를 namespace를 통해서 구현할 수 있다.
namespace WebBroserStuff
{
class WebBroser {...};
void clearBrowser(WebBrowser& sb);
}
WebBrowser처럼 응용도가 높은 클래스는 이런 종류의 편의 함수가 꽤 많이 생길 수 있다. 즐겨찾기에 관련된 함수라든지, 인쇄에 관련된 함수, 쿠키 관리용 함수 등등이 있을 것이다.
이것들을 나누어 놓는 쉽고 깔끔한 방법은 즐겨찾기 관련 편의 함수를 하나의 헤더 파일에 몰아서 선언하고, 쿠키 관련 편의 함수는 다른 헤더 파일에 몰아서 선언하고, 인쇄 관련 편의 함수는 또 다른 헤더 파일에 몰아서 선언하는 것이다.
// "webbrowser.h"
// WebBrowser 관련 core functions
namespace WebBrowserStuff
{
class WebBrowser {...};
void clearBrowser(WebBrowser& wb); // 핵심 관련 기능. 거의 모든 사용자가 써야하는 비멤버함수
}
// "webbrowserbookmarks.h"
namespace WebBrowserStuff
{
// 즐겨찾기 관련 편의 함수
}
// "webbrowsercookies.h"
namespace WebBrowserStuff
{
// 쿠키 관련 편의 함수
}
표준 C++라이브러리가 이러한 구조로 되어있다. 이렇게 사용하면 사용자가 필요한 기능에 대해서만 #include 해서 사용하면 되고 결국 사용자가 실제로 사용하는 구성요소에 대해서만 컴파일 의존성을 고려할 수 있지만 멤버 함수로 사용하게 되면 이런 식으로 기능을 쪼개는 것이 불가능하므로 하나의 클래스는 그 전체가 통으로 정의되어야만 한다.
또, 여러 개의 헤더 파일에 나누어놓으면 편의 함수 집합의 확장도 쉽게 할 수 있다.
요약
- 멤버 함수보다는 비멤버 비프랜드 함수를 자주 쓰도록 하자. 캡슐화 정도가 높아지고, 패키징 유연성도 커지며, 기능적인 확장성도 늘어난다.
'Books > Effective C++' 카테고리의 다른 글
[Effective C++] 25. 예외를 던지지 않는 swap에 대한 지원도 생각해 보자 (0) | 2022.06.12 |
---|---|
[Effective C++] 24. 타입 변환이 모든 매개변수에 대해 적용되어야 한다면 비멤버 함수를 선언하자 (0) | 2022.06.12 |
[Effective C++] 22. 데이터 멤버가 선언될 곳은 private 영역임을 명심하자 (0) | 2022.06.12 |
[Effective C++] 21. 함수에서 객체를 반환해야 할 경우에 참조자를 반환하려고 들지 말자 (0) | 2022.06.03 |
[Effective C++] 20. 값에 의한 전달보다는 상수객체 참조자에 의한 전달 방식을 택하는 편이 대개 낫다 (0) | 2022.05.29 |
댓글
이 글 공유하기
다른 글
-
[Effective C++] 25. 예외를 던지지 않는 swap에 대한 지원도 생각해 보자
[Effective C++] 25. 예외를 던지지 않는 swap에 대한 지원도 생각해 보자
2022.06.12 -
[Effective C++] 24. 타입 변환이 모든 매개변수에 대해 적용되어야 한다면 비멤버 함수를 선언하자
[Effective C++] 24. 타입 변환이 모든 매개변수에 대해 적용되어야 한다면 비멤버 함수를 선언하자
2022.06.12 -
[Effective C++] 22. 데이터 멤버가 선언될 곳은 private 영역임을 명심하자
[Effective C++] 22. 데이터 멤버가 선언될 곳은 private 영역임을 명심하자
2022.06.12 -
[Effective C++] 21. 함수에서 객체를 반환해야 할 경우에 참조자를 반환하려고 들지 말자
[Effective C++] 21. 함수에서 객체를 반환해야 할 경우에 참조자를 반환하려고 들지 말자
2022.06.03