Notice
Recent Posts
Recent Comments
Link
«   2026/05   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
Archives
Today
Total
관리 메뉴

로또

23. 멤버 함수보다는 비멤버 비프렌드 함수와 더 가까워지자. 본문

책/Effective C++

23. 멤버 함수보다는 비멤버 비프렌드 함수와 더 가까워지자.

아롱로또 2023. 11. 20. 14:03

다루는 내용

멤버 함수와 비교했을 때, 비멤버 비프렌드 함수가 가지는 장점을 알아본다. 또한 namespace와 함께 비멤버 비프렌드 함수를 유용하게 작성하는 방법을 다룬다.

 

 

멤버 함수? 비멤버 비프렌드 함수?

웹브라우저를 관리하는 클래스가 있고, 해당 클래스 내에 캐시, 인터넷 사용 기록, 쿠키를 제거하는 함수가 존재한다고 가정해보자.

class WebBrowser{
public:
   void ClearCache();
   void ClearHistory();
   void RemoveCookies();
};

사용자 중에는 위 세 동작을 모두 한 번에 처리하고 싶은 사람도 있을 것이다.

이를 위해, 다음과 같이 함수를 클래스의 멤버 함수로서 ClearEverything()을 제공할 수 있을 것이다.

class WebBrowser{
public:
   void ClearCache();
   void ClearHistory();
   void RemoveCookies();
   
   void ClearEverything(){
      ClearCache();
      ClearHistory();
      RemoveCookies();
   }
};

또는, 다음과 같이 함수를 비멤버 함수로 ClearBrowser()를 제공할 수도 있을 것이다.

void ClearBrowser(WebBrowser& wb){
   wb.ClearCache();
   wb.ClearHistory();
   wb.RemoveCookies();
}

 

객체 지향 법칙에 관련된 이야기를 찾아보면 데이터와 그 데이터를 기반으로 동작하는 함수는 한 데 묶여 있어야 하며, 멤버 함수가 더 낫다고 이야기한다.

하지만 이는 틀렸다. 분명히 객체 지향 법칙은 할 수 있는 만큼 데이터를 캡슐화하라고 주장한다.

위의 코드에서 멤버 함수인 ClearEverything()은 비멤버 함수인 ClearBrowser()보다 캡슐화 측면에서 좋지 않다. 또한 비멤버 함수를 사용하면 WebBroswer 관련 기능을 구성하는 데 있어 패키징 유연성(Packaging Flexibility)이 높아지는 장점이 있는 데다가 이로 인해 얻게 되는 추가적인 이점으로 컴파일 의존도를 낮추고 WebBrowser의 확장성을 높일 수 있다.

 

멤버 함수보다 비멤버 함수가 캡슐화 측면에서 뛰어나다

캡슐화는 객체의 속성과 행위를 하나로 묶고, 실제 구현 내용 일부를 내부에 감추어 은닉하는 것이다.

무언가를 캡슐화를 하면 외부에서 이를 볼 수 없게 되고, 캡슐화하는 것이 늘어날수록 그만큼 외부에서 볼 수 있는 것들이 줄어든다.

외부에서 볼 수 있는 것들이 줄어들면 이들을 바꿀 때 유연성이 커지므로 캡슐화는 충분한 가치가 있다.

 

어떤 객체를 그 객체의 데이터로 설명할 수 있다고 했을 때, 해당 데이터에 직접 접근할 수 있는 코드가 적을수록 해당 데이터는 많이 캡슐화되었다고 말할 수 있다. 데이터에 접근할 수 있는 코드의 수는 데이터에 접근할 수 있는 함수의 개수라고 할 수 있을 것이다. 어떤 데이터에 접근하는 함수가 많으면, 해당 데이터의 캡슐화 정도는 낮다.

 

private 멤버로 되어있는 데이터의 경우, 이에 접근할 수 있는 함수의 수는 해당 클래스의 멤버 함수와 friend 함수 뿐이다.

멤버 함수는 해당 클래스의 모든 데이터에 접근할 수 있는 반면, 비멤버 비프렌드 함수는 그렇지 못하다. 즉, 캡슐화의 정도가 멤버 함수보다 비멤버 함수가 더 뛰어나다고 할 수 있다.

 

Namespace의 활용

비멤버 비프렌드 함수인 ClearBrowser 함수를 다른 유틸리티 클래스의 정적 멤버 함수로 만드는 방법도 있겠지만, C++로는 namespace를 이용하여 자연스러운 방법을 구현할 수 있다. ClearBrowser를 비멤버 함수로 두되, WebBrowserStuff와 같은 namespace 안에 두는 것이다.

namespace는 클래스와 달리 여러 개의 소스 파일에 나뉘어 흩어질 수 있다. ClearBroswer와 같은 함수는 편의상 준비한 함수로, WebBroswer과 같은 응용도가 높은 클래스에서 이러한 편의 함수는 보다 다양하게 만들어질 수 있다. (즐겨찾기, 인쇄, 쿠키 관리 등 ...)

 

편의 함수들을 깔끔하게 나누어 놓기 위해 다음과 같은 방법을 추천한다.

WebBrowser.h

namespace WebBrowserStuff{
   // 클래스 자체
   class WebBrowser{
   public:
      void ClearCache();
      void ClearHistory();
      void RemoveCookies();
   };
   ... // 핵심 기능, 거의 모든 사용자가 써야 하는 비멤버 함수들
};

WebBrowserCookie.h

namespace WebBrowserStuff{
   // 쿠키 관련 편의 함수들
};

 

WebBrowserBookmark.h

namespace WebBrowserStuff{
   // 즐겨찾기 관련 편의 함수들
};

 

표준 C++ 라이브러리도 이와 같은 구조를 사용하고 있다.

namespace std에 속한 모든 것들이 <C++StandardLibrary> 헤더 같은 것에 전부 모여있지 않고, 몇 개의 기능과 관련된 함수들이 수십 개의 헤더(<vector>, <algorithm>, <memory>) 등에 흩어져 선언되어 있어 사용자는 필요한 것만 include 하면 된다.

 

이는 사용자가 실제로 사용하는 구성요소에 대해서만 컴파일 의존성을 고려할 수 있게 해준다.

또한, 필요한 기능이 있으면 namespace에 비멤버 비프렌드 함수를 추가하면 되므로 편의함수 집합의 확장면에서도 용이하다.

 

이것만은 잊지 말자!

  • 멤버 함수보다는 비멤버 비프렌드 함수를 자주 쓰도록 하자. 캡슐화 정도가 높아지고, 패키징 유연성도 커지며 기능적인 확장성도 늘어난다.

 

참고 자료

https://ko.wikipedia.org/wiki/%EC%BA%A1%EC%8A%90%ED%99%94

 

캡슐화 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 캡슐화(영어: encapsulation)는 객체 지향 프로그래밍에서 다음 2가지 측면이 있다:[1][2] 객체의 속성(data fields)과 행위(메서드, methods)를 하나로 묶고,[3][4] 실제 구현

ko.wikipedia.org