본문 바로가기
서적 정리/Effective C++

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

by 민돌이2 2021. 12. 14.

객체 지향 법칙은 할 수 있는 만큼 데이터를 캡슐화하라고 한다.

솔직히 제목을 보고 무슨 개소리를 하는거지 싶다. 어차피 객체에 대한 함수일텐데 왜 객체 밖에다가 만들라는 거지? 캡슐화랑 무슨 관련이 있단 소리지 싶다.

 

웹브라우저를 나타내는 클라스가 있다고 가정해보자. 이 클라스에 캐시를 비우는 함수, 방문한 URL의 기록을 지우는 함수, 쿠키를 제거하는 함수가 있을 것이다. 그리고 이 세가지를 동시에 하는 멤버 함수를 구현할 수도 있다.

class WebBrowser
{
public:
	void clearCach(); //캐시 삭제
	void clearHistory(); //URL 삭제
	void removeCookies(); //쿠키 삭제
	void clearEverything() //캐시, URL, 쿠키 삭제
	{
		clearCach();
		clearHistory();
		removeCookies();
	}
};

 

세가지를 동시에 삭제하는 함수는 비멤버 함수로 구현할 수 있을 것이다.

void clearEverything(WebBrowser& wb)
{
	wb.clearCach();
	wb.clearHistory();
	wb.removeCookies();
}

 

비멤버 버전인 clearEvertything 함수는 관련 기능을 구성하는 데 있어서 패키징 유연성(packaging flexibility)이 높아지는 장점이 있고, 이로 인해 컴파일 의존도도 낮추고 WebBrowser의 확장성도 높일 수 있다.

 

객체 지향 법칙적으로 보면 데이터와 그 데이터를 기반으로 동작하는 함수는 한 데 묶여 있어야 하므로 멤버 함수로 구현하는게 낫다고 생각할 수 있다. 하지만 멤버 함수보다 비멤버 함수로 구현한게 캡슐화 정도가 강하다.

캡슐화하는 것이 늘어나면 그만큼 밖에서 볼 수 있는 것들이 줄어든다. 즉, 변경 자체가 영향을 줄 수 있는 범위가 변경된 것을 볼 수 있는 것들로 한정되기 때문에, 제한된 사용자들밖에 영향을 주지 않는 융통성을 확보할 수 있다는 뜻이다.

 

비멤버 비프렌드 함수는 어떤 클래스의 private 멤버 부분을 접근할 수 있는 함수의 개수를 늘리지 않으므로 캡슐화 정도가 강해진다고 할 수 있다. 여기서 주의할게 비멤버 비프렌드 함수에만 적용된다는 것이다. friend 함수는 private 멤버에 대한 접근권한이 해당 클래스의 멤버 함수가 가진 접근권한과 똑같기 때문에, 캡슐화에 대한 영향 역시 같다.

 

확정성은 왜 높아진다는 것일까?

발상의 전환인데 생각해보자. 비멤버 비프렌드 함수를 네임스페이스로 구현한다면 어떤식으로 확장이 가능할까?

std 네임스페이스에 속한 모든 것들이 <C++StandardLibrary> 헤더 같은 것에 모조리 들어가 한 통으로 섞여 있지않고, 몇 개의 기능과 관련된 함수들의 수십 개의 헤더에 흩어져 선언되어 있다. <vector>, <algorithm>, <memory>등을 선언할 때 만약 vector기능만 필요하면 #include <memory>를 할 필요 없이 #include <vector>만 선언한다. 즉, 사용자가 실제로 사용하는 구성요소에 대해서만 컴파일 의존성을 고려할 수 있게 된다(다른 방법으로 31장 참고).

//TestA.h
namespace AAA
{
	void PrintAAA() { std::cout << "TESTA" << std::endl; }
}

//TestB.h
namespace AAA
{
	void PrintBBB() { std::cout << "TESTB" << std::endl; }
}

//Main.cpp
int main()
{
	AAA::PrintAAA();
	AAA::PrintBBB();

	system("Pause");
	return 0;
}

똑같은 네임스페이스 안에 비멤버 프렌드 함수를 다른 헤더파일로 분리 시키면 원하는 편의함수가 있는 헤더파일만 include하면 되기 때문에 편해진다. 같은 네임스페이스에 비멤버 비프렌드 함수를 추가하고 원하는 헤더 파일에 집어넣던지 아니면 새로 헤더파일을 만들면 되기 때문에, 확장도 쉬워진다. 이런 확장성은 멤버 함수로는 불가능한 방법이다. 하지만 기초 클래스의 캡슐화된 멤버 데이터에 대한 접근권한이 없기 때문에 잘 생각해서 사용하자.

 

이것만은 잊지 말자

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

 

728x90

댓글