본문 바로가기

프로그래밍/C++

[C++] 헤더파일을 나누어 은닉화 구현하기

[C++] 헤더파일을 나누어 은닉화 구현하기

배경

이 내용은 모듈화에 대한 생각으로부터 시작합니다. 저는 개인적으로 어떤 코드 조각이 큼지막한 것을 꽤 싫어합니다. 특히 헤더가 지저분한 것은 딱 질색입니다. 일반적으로 헤더는 사용자가 쓰기에 일목요연하고 정리된 모습을 보여줘야 한다고 생각합니다. 그러기 위해서는 필요에 의한 것(객체 혹은 함수)들과 사용자에게 제공하는 것들을 구분할 필요가 있습니다. 이에 관하여 흥미로운 내용을 [The C++ Programming Language]에서 발견하였고 그 내용을 간단히 정리하고자 합니다.

사용자와 구현자

일반적으로 어떠한 코드 조각(Code segmant)를 구현하였을 때, 그 코드 조각이 필요한 사람들은 대부분 사용자구현자 로 구분할 수 있습니다. 구현자는 코드 조각의 세세한 내용까지를 필요로 하는 반면, 사용자는 그 모듈을 어떻게든 사용할 수 있는 방법만 알면 됩니다. 그래서 나온 내용이 설계(Interface)와 구현(Implementation)의 분리이지요. 이제부터 설명하고자 하는 내용은 설계와 구현의 분리에 대한 C++에서의 이용 방법입니다.

클래스의 은닉화(Encapulation)

객체지향 언어의 클래스에서는 설계와 구현의 분리를 위해 publicprivate, protected라는 접근 권한을 제공합니다. 이 내용은 클래스의 사용자로 하여금 어디까지가 이용 가능한 것인지를 명시해줍니다. 하지만 더욱 좋은 은닉화는 사용자에게 정보조차 제공하지 않는 것이라고 여겨집니다. 즉, 너는 이러이러한 내용만 알고 있었도 이 내용을 쓰는 데에 하등의 문제가 없다고 알리는 것이죠. 이것을 위해서 필요한 것이 함수의 중복 선언입니다.

함수의 중복 선언

C++에서 정의는 한 번밖에 가능하지 않지만 선언은 얼마든지 할 수 있습니다. 이를 이용하면 사용자가 필요로 하는 정도에 따라 필요한 내용만을 전달할 수 있습니다. 즉, 같은 내용에 대해 해당하는 함수의 내용만을 주는 것입니다. 일례를 들면 다음과 같습니다.

file: adder.h
struct Complex { float r, i; };
void Expr( ostream &os );	
file: adder_impl.h
#include "adder.h"
struct Complex;
void Expr( ostream &os );	
const Complex Generate();

사용자에게 제공하는 헤더는 adder.h고 구현자들이 사용할 헤더는 adder_impl.h 입니다. 구현은 adder_impl.cppadder_impl.h를 포함(include)하여 구현하면 됩니다.

여러 계층에게 다른 종류의 헤더 주기

사실 굳이 중복 선언이 따로 필요한 것은 아닙니다. adder_impl.h에는 void Expr()이 굳이 있을 필요는 없습니다. 다만 adder.h 말고도 adder_advance.h 등과 같이 다른 필요를 가진 계층이 나타났다면 그에 맞는 함수들만 쭉 적어주면 좋습니다. 단, 주의점은 구현부에서는 설계만 되어있는 모든 파일을 포함해주어야만 합니다.

결론

별 내용은 아닙니다. 여기서 이용한 것은 단순히 함수가 중복 선언이 가능하다는 사실밖에는 없습니다. 하지만 헤더 파일과 소스 파일에 그 파일 이름에 맞는 클래스 하나만 존재하는 프로그래밍만 있지 않다는 사실을 다시 한 번 환기할 수 있는 기회가 되었으면 좋겠습니다.