Modern C++ Design — 단위전략 기반의 클래스

Younghyun Jo
Sep 6, 2018 · 5 min read

C++을 사용하는 프로젝트에 참여하게 되었다. C++은 언어적으로 객체개념이 반영되었고, 다형성을 위해 오버로딩, 오버라이딩 등을 지원하는 언어로 알고 있었다. C를 구조체와 함수 포인터 적극적으로 사용하여 객체지향 언어처럼 개발을 했기 때문에 C++도 자신이 있었다. 하지만, C++11은 새롭게 탄생하였다. 함수형 특성을 적극적으로 반영해 절차형과 함수형의 특성을 모두 갖춘 언어로 변했다. 템플릿 메타 프로그래밍(TMP) 기법을 공부하던 중 ‘제너릭 프로그래밍과 디자인 패턴을 적용한 Modern C++ Design’ 책을 추천받고, 공부한 내용을 남긴다.


유연한 다지인을 방해하는 다중상속

  1. 구조적 문제 : 다중상속은 클래스를 포개어 놓고, 각각의 멤버를 접근하기 위한 단순한 규칙만을 제공할 뿐이다. 이는 단순한 경우를 제외하고는 한계를 가진다. 원하는 기능을 하려면, 상속된 클래스 간의 동작을 면밀히 조율해 주어야 한다.
  2. 상태 처리의 문제 : 다양한 동작 요소들은 그 상태가 정확기 동기화 되어야 한다.

템플릿(Template)의 이점

템플릿은 프로그래머가 선택한 자료형에 따라 컴파일 타임에 코드를 생성한다.

일반화된 템플릿을 선언하고, 자료형에 따라 별도의 일을 처리하고 싶을 땐 특화된 템플릿(Specialized template)을 사용할 수 있다. 또한 다중 인자를 가지는 클래스 템플릿은 템플릿 부분 특화도 가능하다.

하지만, 템플릿에도 몇 가지 문제점이 있다.

  1. 클래스의 멤버 변수를 특화시킬 수 없으며, 오직 멤버 함수에 대에서만 가능하다.
  2. 클래스 템플릿을 구현할 때 각각의 멤버 함수에 대해 오직 하나의 기본 값만 구현 가능하다.
  3. 템플릿 인자가 여러개인 멤버함수는 특화가 불가능하다.
//템플릿 인자가 하나인 클래스 템플릿
template <class T> class
widget {
void Fun() { ...}
};
//OK. 템플릿 인자가 하나이기 때문에 특화
template<> Widget<char>::Fun() {
...
}
//템플릿 인자가 두 개인 클래스 템플릿
template<class T, class U> class Gadget {
void Fun() { ... }
}
// ERROR. 템플릿 인자 하나만 특화시킬 수 없다.
template <class U> void Gadget<char, U>::Fun()
{
...
}

단위전략과 단위전략 클래스

— 용어설명 —

  • 단위전략(policy)이란 매우 단순한 동작이나 구조만을 가지는 작은 클래스이다. 특정 문제를 해결하는 데 꼭 맞는 인터페이스를 갖도록 디자인 된다.
  • 단위전략 클래스는 단위전략에 대한 구체적인 구현을 일컷는다.
  • 단위전략 기반의 클래스 디자인(policy-based class design)이란 단위전략을 모아서 복합된 기능을 하는 새로운 클래스를 만들어 내는 디자인 방식을 말한다.
  • 호스트·호스트 클래스는 하나 이상의 단위전략을 사용하는 클래스를 일컷는다.

예를 들어 Creator 단위전략을 정의해보자. Creator는 Create라는 멤버 함수를 가지고 있으며, 이 멤버 함수는 자료형 T의 포인터를 반환하는 함수이다. 의미상, Create 함수는 매 호출마다 새로운 T 형의 객체에 대한 포인터를 반환해 주며, 그 객체가 생성되는 방식은 단위전략의 구현 방법에 따라 달라진다. 이처럼 Creator 단위전략은 인터페이스만 정의하고 있으며 구체적인 구현은 단위전략 클래스에서 이뤄진다.

//new 연산자를 사용한 단위전략 클래스
template <class T> struct
OpNewCreator {
static T* Create() {
return new T;
}
};
//malloc을 사용한 단위전략 클래스
template <class T> struct
OpMallocCreator {
static T* Create() {
void* buf = std::malloc(sizeof(T));
return new(buf) T;
}
};

Creator 단위전략을 사용하는 클래스 디자인

// 라이브러리 코드
template <class CreationPolicy> class
WidgetManager : public CreationPolicy {
...
};
// 어플리케이션 코드
WidgetManager<OpNewCreator> MyWidgetMgr;

단위전략의 핵심은 MyWidgetMgr 객체를 생성할 때 new 연산자를 사용할 지, malloc 함수를 사용할지에 대한 선택은 사용자의 몫으로 남겨두었다는 점이다.

단위전략 클래스 간의 조합

단위전략의 유용성은 단위전략 클래스들을 조합하여 사용할 때 극대화 된다.

template 
<
class T,
template<class> class CheckingPolicy,
template<class> class ThreadingModel
>
class SmartPtr;

SmartPtr은 세 계의 템플릿 인자를 가진다. 첫 번째 인자는 포인터가 가리킬 자료형이고, 나머지 두 가지는 선택해야 할 단위전략을 나타냅니다. 이처럼 두 개의 단위 전략을 하나의 SmartPtr에서 사용할 수 있습니다.

클래스를 단위전략으로 분리해내기

  • 클래스의 동작을 구성하는 데 필요한 결정 사항을 파악
  • 한 가지 이상의 방법으로 수행될 수 있는 일면 클래스부터 단위전략으로 분리
  • 서로 상호작용하지 않는 요소를 찾아 분리

책에서는 단위전략에 대해 어렵고 장황하게 설명을 했다. 하지만, 내가 이해한 단위전략은 스트래터지 패턴과 유사하다. 단, 템플릿을 사용하여 컴파일 타임에 적용시켰다.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade