- 클래스 설계는 타입 설계와 같다. 새로운 타입을 정의하기 전에 몇 가지 고려사항을 점검해 보자.
클래스 설계는 타입 설계
여느 객체 지향 프로그래밍 언어처럼, C++에서 새로운 클래스를 정의한다는 것은 새로운 타입을 정의하는 것과 같다.
C++ 개발을 한다는 것은 타입을 새로 만드는 일과 같으며 함수와 연산자를 오버로드하고, 메모리 할당 및 해제를 제어하며, 객체 초기화 및 종료처리를 정의하는 작업 모두 관리해 주어야 한다.
좋은 클래스를 설계하는 것은 꽤 어렵다. 문법이 자연스럽고, 의미구조가 직관적이며, 효율적인 구현이 가능해야 한다.
성능 또한 무시할 수 없는 부분이다.
다음은 좋은 클래스를 설계하기 위해 고려해 볼 사항 몇 가지이다.
- 새로 정의한 타입의 객체 생성 및 소멸은 어떻게 이루어져야 하는가?
생성과 소멸이 어떻게 처리되는가에 따라 클래스 생성자 및 소멸자의 설계가 바뀐다. 그뿐 아니라 메모리 할당 함수(operator new, operator new[], operator delete, operator delete[])를 직접 작성할 경우 이들 설계에 영향을 미친다. - 객체 초기화는 객체 대입과 어떻게 달라야 하는가?
생성자와 대입 연산자의 동작과 차이점을 결정짓는 요소이다. 초기화와 대입을 헷갈리지 않는 것이 중요하다. - 새로운 타입이 가질 수 있는 적법한 값에 대한 제약은 무엇으로 잡을 것인가?
클래스의 데이터 멤버의 몇 가지 조합 값만은 반드시 유효해야 한다. 이런 조합을 클래스의 불변속성이라고 하며, 클래스 차원에서 지켜주어야 하는 부분이다. 이 불변속성에 따라 클래스 멤버 함수 안에서 해 주어야 할 에러 점검 루틴이 좌우되는데, 특히 생성자, 대입 연산자, setter 함수는 불변속성에 많이 좌우된다. 그뿐 아니라 불변 속성은 함수가 발생시키는 예외에도 영향을 미치며, 예외지정을 쓴다면 그 부분에도 영향을 준다. - 기존의 클래스 상속 계통망에 맞출 것인가?
이미 갖고 있는 클래스로부터 상속을 시킨다고 하면, 당연히 부모 클래스에 의해 제약을 받게 된다. 특히 멤버 함수가 가상인가 비가상인가의 여부가 가장 큰 요인이다. 설계한 클래스를 다른 클래스들이 상속할 수 있게 만들기로 결정했다면, 이에 따라 함수의 가상 함수 여부가 결정된다. 특히 소멸자가 그렇다. - 어떤 종류의 타입 변환을 허용할 것인가?
제작한 타입은 결국 기존의 수많은 타입들과 어울려야 한다. 타입 사이에 변환이 암시적 변환을 허용하고 싶다면 타입 변환 함수를 만들어 놓거나 인자 한 개로 호출될 수 있는 비명시호출 생성자를 변환될 클래스에 넣어두어야 한다.
명시적 타입 변환만 허용하고 싶다면 해당 변환을 맡는 별도 이름의 함수를 만들되 타입 변환 연산자 혹은 비명시호출 생성자는 만들지 말아야 한다. - 어떤 연산자와 함수를 두어야 의미가 있을까?
클래스 안에 선언할 함수가 여기서 결정된다. 어떤 것들은 멤버 함수로 적당할 것이고, 몇몇은 그렇지 않을 것이다. - 표준 함수들 중 어떤 것을 허용하지 말 것인가?
private로 선언해야 하는 함수가 여기에 해당한다. - 새로운 타입의 멤버에 대한 접근권한을 어느 쪽에 줄 것인가?
어떤 클래스 멤버를 public, protected, private 영역에 둘 것인가를 결정하는 데 도움이 될 질문이다.
또한, 프렌드로 만들어야 할 클래스 및 함수를 정하는 것은 물론이고 한 클래스를 다른 클래스에 중첩시켜도 되는가에 대한 결정을 내리는 데도 도움이 될 것이다. - 선언되지 않은 인터페이스로 무엇을 둘 것인가?
타입이 제공할 보장이 어떤 종류일까에 대한 질문으로서, 보장할 수 있는 부분은 수행 성능 및 예외 안전성 그리고 자원 사용이다. 이들에 대한 보장을 결정한 결과는 클래스 구현에 있어서 제약으로 작용하게 된다. - 새로 만드는 타입이 얼마나 일반적인가?
타입을 정의하는 것은 타입 하나를 정의하는 데 그치지 않을 수 있다. 동일 계열의 타입군 전체에 적용될지 모르기 때문이다. 그렇다면 새로운 클래스를 정의하는 것이 새로운 클래스 템플릿을 정의하는 것일 수 있다. - 정말로 꼭 필요한 타입인가?
기존 클래스에 대해 기능 몇 개가 아쉬워서 파생 클래스를 새로 만들고 있다면, 차라리 간단하게 비멤버 함수라든지 템플릿을 몇 개 더 정의하는 편이 낫다.