스토리텔링 개발자

[Effective C++] 23. 비멤버 비프렌드 함수 본문

개발/Effective C++

[Effective C++] 23. 비멤버 비프렌드 함수

김디트 2024. 6. 18. 08:56
728x90

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

 

 

 

멤버 버전 vs 비멤버 버전
  • 아래 예시에서 clearEverything과 clearBrowser 중 어떤 것이 나을까?
class WebBrowser
{
public:
    ...
    void clearCache();
    void clearHistory();
    void removeCookies();
    ...
    
    void clearEverything(); // 멤버 버전. clearCache, clearHistory, removeCookies를 호출
};

void clearBrowser(WebBrowser& wb) // 비멤버 버전
{
    wb.clearCache();
    wb.clearHistory();
    wb.removeCookies();
}
  • 객체 지향 법칙이란?
    • 데이터와 그 데이터를 기반으로 동작하는 함수는 한 데 묶여 있어야 하며, 멤버 함수가 더 낫다?
    • 하지만 이는 객체 지향 방법의 몰이해 상태에서 나온 제안이다.
  • 비교
    • clearEverything은 clearBrowser보다 캡슐화 정도에서 오히려 형편없다.
      • clearEverything은 공개되지 않은 것들을 활용할 여지가 있기 때문.
    • 비멤버 함수가 패키징 유연성(packaging flexibility)이 높다.
    • 그래서 컴파일 의존도가 낮으며 WebBrowser의 확장성도 높아질 수 있다.

 

 

 

캡슐화
  • 캡슐화를 하면 이미 있는 코드를 바꾸더라도 제한된 사용자들밖에 영향을 주지 않는 융통성이 생긴다.
    • 캡슐화하면 외부에서 볼 수 없게 된다. 즉, 바꿀 때 필요한 유연성이 커진다는 의미이므로.
  • 비멤버 비프렌드 함수는 private 멤버 부분을 접근할 수 있는 함수의 갯수를 늘리지 않으므로 캡슐화 정도가 더 높다고 할 수 있다.

 

 

 

비멤버 함수를 제작할 때 주의점
  • 비프렌드(non-friend)함수로 해야 한다.
    • 프렌드 함수는 해당 클래스의 멤버 함수가 가진 접근권한과 동일하므로 멤버 함수와 동일하다.
  • 함수가 어떤 클래스의 비멤버가 되어야 한다는 건, 그 함수가 다른 클래스의 멤버가 될 수 없다는 뜻은 아니다.
    • 아무튼 이 함수가 WebBrowser 클래스의 멤버(혹은 프렌드)가 아니기만 하면 된다.
    • private 멤버의 캡슐화에 영향을 주지 않는다는 점이 중요하기 때문이다.

 

 

 

C++로 구현하는 더 자연스러운 방법
  • clearBrowser를 비멤버 함수로 두되, WebBrowserStuff와 같은 네임스페이스 안에 두는 방법.
namespace WebBrowserStuff
{
    class WebBrowser { ... };
    void clearBrowser(WebBrowser& wb);
    ...
};

 

 

 

네임스페이스를 활용한 헤더 쪼개기
  • 클래스와 달리 네임스페이스는 여러 개의 소스파일로 나뉘어 흩어질 수 있다.
  • 편의 함수에서는 사용자 수준 이상의 기능을 제공할 수 없다.
  • 이를 이용해 기능 별로 헤더를 분리한다.
// Webbrowser.h
namespace WebBrowserStuff
{
    class WebBrowser { ... }; // 핵심 기능
    ...
}

// Webbrowserbookmark.h
namespace WebBrowserStuff
{
    ... // 즐겨찾기 관련 편의 함수만 포함
}

// Webbrowsercookies.h
namespace WebBrowserStuff
{
    ... // 쿠키 관련 편의 함수만 포함
}
  • 사실 표준 C++ 라이브러리가 이런 구조이다.
    • std 네임스페이스에 속한 것들이 기능 별로 수십 개의 헤더로 흩어져 선언되어 있다.
    • <vector>, <algorithm>, <memory> 등
    • 사용자눈 실제로 사용하는 구성요소에 대해서만 헤더를 포함하여, 컴파일 의존성을 고려할 수 있다.
  • 확장이 손쉬워진다
    • 해당 네임스페이스에 비멤버 비프렌드 함수를 원하는 만큼 추가해 주기만 하면 그게 확장이다.

 

728x90
Comments