[Effective C++] 19. 클래스 설계는 타입 설계와 똑같이 취급하자

Effective C++ 제 3판 - Chapter 4 - 1


클래스를 정의한다는 것은 새로운 타입을 하나 정의하는 것과 같습니다. C++ 개발자로서 여러분이 보내는 시간은 여러분 자신의 타입 시스템을 키워나가는 데 들어가는 시간인 셈입니다. 바꿔 말해 여러분은 클래스 설계자로 그치지 않고 타입 설계자라는 막강한 권위를 가지고 있다는 얘기지요.

어떤 클래스들을 설계하든 간에 사실상 모든 경우에 여러분의 후두부를 괴롭힐 질문들을 아래에 모아보았습니다. 이들 질문의 대답에 따라 설계를 제한하는 것들이 생기게 되는데, 이 부분 역시 신경 쓰지 않으면 안됩니다. 그럼 시작하죠.

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


이 부분이 어떻게 되느냐에 따라 클래스 생서자 및 소멸자의 설계가 바뀝니다. 그 뿐 아니라 메모리 할당 함수를 직접 작성할 경우에는 이들 함수 설계에도 영향을 미칩니다. (항목8 참조)

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


생성자와 대입 연산자의 동작이 어떻게 달라져야 하는지에 대해 생각해보아야 한다는 것이지요. 초기화와 대입을 헷갈리지 않는 것이 가장 중요합니다. 항목4 참조

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


‘값에 의한 전달’은 복사 생성자 입니다. 즉 복사 생성자가 어떤 의미를 줄 것인지 입니다. 예를 들어 unique_ptr 같은 경우는 복사 생성자를 사용할 경우 원래의 객체는 소유권을 잃게 되겠지요.

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


전부다는 아니지만, 클래스 데이터 멤버의 몇 가지 조합 값만은 반드시 유효해야만 합니다. 이런 조합을 가리켜 클래스의 불변속성이라고 하며, 클래스 차원에서 지켜주어야 하는 부분입니다.

이 불변속성에 따라 클래스 멤버 함수 안에서 해 주어야 할 에러 점검 루틴이 좌우되는데 특히 생성자, 대입 연산자, 각종 “쓰기(setter)” 함수는 불변속성에 많이 좌우됩니다. 그뿐 아니라, 불변속성은 여러분의 함수가 발생시키는 예외에도 영향을 미치며, 혹시나 여러분이 예외 지정을 쓴다면 그 부분에도 영향을 줍니다.

5. 기존의 클래스 상속 계통망(inheritance graph)에 맞출 것인가?


클래스를 만들 때 기존의 클래스로들이 상속할 수 있게 만들지의 여부, 그리고 상속할 수 있게 만들자고 결정했다면, 이에 따라 멤버 함수의 가상 함수 여부가 결정됩니다. 특히 소멸자가 그렇지요.

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


우리가 만든 타입은 결국 기존의 타입과 어울려야 하는 운명을 짊어집니다. 앞서 공부했던 암시적 & 명시적 변환을 적재적소에 사용하도록 만들어야겠지요. 명시적, 암시적 변환의 예는 항목15에서 보실 수 있습니다.

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


우리가 만든 클래스 안에 선언할 함수가 바로 여기서 결정됩니다. 어떤 것들은 멤버 함수로 적당할 것이고, 또 몇몇은 그렇지 않겠지요. (항목 23, 24, 26 참조)

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


private로 선언해야 하는 함수가 바로 여기에 해당할 것 입니다.

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


어떤 클래스 멤버를 public, protected, private 영역에 둘 것인가를 결정하는데 도움을 주게 될 질문입니다.

또한 프렌드로 만들어야 할 클래스 및 함수를 정하는 것은 물론이고 한 클래스를 다른 클래스에 중첩시켜도 되는가에 대한 결정을 내리는 데도 이 질문이 여러분들 도와줄 것 입니다.

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


여러분이 만들 타입이 제공할 보장이 어떤 종류인가에 대한 질문으로서, 보장할 수 있는 부분은 수행 성능 및 예외 안전성 그리고 자원 사용 등 입니다. 이들에 대해 보장하겠다고 결정한 결과는 클래스 구현에 있어서 제약으로 작용하게 됩니다. (항목29)

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


실상은 타입 하나를 정의하는 것이 아닐지도 모릅니다. 여러분이 정의하는 것이 동일 계열의 타입군(family of types) 전체일지도 모른다는 것이지요. 진짜 그렇다면 여러분이 원하는 것은 새로운 클래스가 아닙니다. 새로운 클래스 템플릿을 정의해야 할 것 입니다.

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


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

End Note


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

Reference


  • Effective C++ (Scott Meyers)

Updated:

Leave a comment