Item 19: 클래스 설계는 타입 설계와 똑같이 취급하자

객체 지향 프로그래밍 언어의 특징은 새로운 타입을 하나 정의할 수 있다는 점이다. (클래스로) 이는 언어 관점으로 봐도 막강한 권력이며 C++의 특성상 여기에 메모리 할당/해제의 개념까지 묶여있다. 이러한 영역에서 객체의 함수(오버로딩, 오버라이딩) 다형성의 개념과 생명주기까지 전부 관리해야 하니 신중하게 설계해야 한다.

좋은 클래스를 설계하기란 어렵고 한번에 이뤄지는 것이 아니다. 좋은 타입이란 문법이 자연스럽고, 의미구조가 직관적이며 효율적인 구현이 한 가지 이상 가능해야 하는데, C++에서는 충분한 고민 없이 클래스 정의를 했다가는 이 세 가지 중 어느 것도 달성하기 힘들 수 있다.

효과적인 클래스 설계를 위한 문답이 있으니 클래스를 설계하기 전 해당 문답에 답해보면 좋을 것 같다.

새로 정의한 타입의 객체 생성 및 소멸은 어떻게 이루어져야 하는가?

이 부분이 어떻게 되느냐에 따라 클래스 생성자 및 소멸자의 설계가 바뀐다. 그뿐 아니라 메모리 할당 함수(operator new, operator new[], operator delete, operator delete[])를 직접 작성할 경우 함수의 설계에도 영향을 미친다.

객체 초기화는 객체 대입과 어떻게 달라야 하는가?

생성자와 대입 연산자의 동작 및 둘 사이의 차이점을 결정 짓는 요소다. 초기화와 대입을 헷갈리지 않는 것이 가장 중요하다. 각각 해당되는 함수 호출이 아예 다르기 때문이다.

새로운 타입으로 만든 객체가 값에 의해 전달되는 경우에 어떤 의미를 줄 것인가?

어떤 타입에 대해 ‘값에 의한 전달’을 구현하는 쪽은 바로 복사 생성자이다.

새로운 타입이 가질 수 있는 적법한 값에 대한 제약은 무엇으로 잡을 것인가?

전부는 아니지만, 클래스의 데이터 멤버의 몇 가지 조합 값만은 반드시 유효해야 한다. 이런 조합을 가리켜 클래스의 불변속성이라고 하며, 클래스 차원에서 지켜주어야 하는 부분이다. 이 불변속성에 따라 클래스 멤버 함수 안에서 해 주어야 할 에러 점검 루틴이 좌우되는데, 특히 생성자, 대입 연산자, 각종 쓰기 함수는 불변속성에 의해 많이 좌우된다.

기존의 클래스 상속 계통망에 맞출 것인가?

이미 갖고 있는 클래스로부터 상속을 시킨다고 하면, 당연히 설계는 이들 클래스에 의해 제약을 받게 된다. 특히 멤버 함수가 가상인가 비가상인가의 여부가 가장 큰 요인이다. 직접 만든 클래스를 다른 클래스들이 상속할 수 있게 만들자고 결정했다면, 이에 따라 멤버 함수의 가상 함수 여부가 결정된다.

어떤 종류의 타입 변환을 허용할 것인가?

직접 만든 타입은 결국 기존의 수많은 타입들이 어울려야 하는 운명을 짊어진다. 타입과 다른 타입 사이에 변환 수단이 있어야 할지 여부를 결정해야 한다. 이는 클래스 설계에 큰 영향을 미친다.

어떤 연산자와 함수를 두어야 의미가 있을까?

클래스 안에 선언할 함수가 여기서 결정된다.

표준 함수들 중 어떤 것을 허용하지 말 것인가?

private로 선언해야 하는 함수가 여기에 해당된다.

새로운 타입의 멤버에 대한 접근권한을 어느 쪽에 줄 것인가?

어떤 클래스 멤버를 public, protected, private로 선언할지 결정하는 것이다. 이는 클래스 설계에 큰 영향을 미친다.

‘선언되지 않은 인터페이스’로 무엇을 둘 것인가?

직접 만들 탕비이 제공할 보장이 어떤 종류일지 고민해야 한다. 보장할 수 있는 부분은 수행 성능 및 예외 안전성 그리고 자원 사용이다. 이들에 대해 보장하겠다고 결정한 결과는 클래스 구현에 있어서 제약으로 작용하게 된다.

새로 만드는 타입이 얼마나 일반적인가?

실상은 타입 하나를 정의하는 것이 아닐지도 모른다. 직접 정의하는 것이 동일 계열의 타입군 전체일지도 모른다. 어쩌면 템플릿을 정의해야 할 것이다.

정말로 꼭 필요한 타입인가?

기존의 클래스에 대해 기능 몇 개가 아쉬워서 파생 클래스를 새로 뽑고 있다면, 차라리 간단하게 비멤버 함수라든지 템플릿을 몇 개 더 정의하는 편이 낫다.

정리

어느하나 빼 먹을 수 없는 질문이면서 그만큼 효과적인 클래스를 정의하는 것이 무척이나 어렵다는 말이다. 하지만 이러한 설계에 대한 진지한 고민을 함으로써 가치있는 타입을 만들어 낼 수 있다.

  • 클래스 설계는 타입 설계다. 새로운 타입을 정의하기 전에, 이번 항목에 나온 모든 고려사항을 빠짐없이 점검해 보자.

태그: ,

카테고리:

업데이트:

댓글남기기