항목 19 클래스 설계는 타입 설계와 똑같이 취급하자
19.1 클래스 설계 고려사항
C++에서 새로운 클래스를 정의하는 것은 새로운 타입을 정의하는 것과 같다. 그렇기 때문에 클래스를 설계할 때는 마치 기본 타입을 설계하는 것처럼 많은 정성과 노력이 필요하다. 그럼 클래스를 효과적으로 설계하려면 어떤 것들을 고려해야 하는지 우선 파악해보자.
- 새로운 타입의 객체 생성 및 소멸은 어떻게 이루어져야 하는가?
이 부분에 따라서 클래스 생성자와 소멸자의 설계가 바뀐다.
- 객체 초기화는 객체 대입과 어떻게 달라야 하는가?
(복사) 생성자와 복사 대입 연산자의 동작을 결정하는 요소이다. 초기화와 대입을 헷갈리지 않는 것이 중요하다.
- 새로운 타입으로 만든 객체가 값에 의해 전달되는 경우, 어떤 의미를 부여할 것인가?
어떤 타입에 대해 값에 의한 전달을 구현하는 쪽은 복사 생성자이다.
- 새로운 타입이 가질 수 있는 적법한 값에 대한 제약은 무엇으로 잡을 것인가?
클래스 데이터 멤버의 몇 가지 조합은 유효해야 한다. 이런 조합을 가리켜 클래스의 불변성(invariance)이라 한다. 이 불변성에 따라 특히 생성자, 대입 연산자, 쓰기(setter) 함수의 에러 점검 루틴이 크게 좌우된다.
- 기존 클래스의 상속 계통망(inheritance graph)에 맞출 것인가?
클래스를 상속시킨다고 하면 클래스 설계는 이 클래스에 의해 제약을 받게 된다. 특히, 멤버 함수의 가상·비가상 여부가 가장 큰 요인이다.
- 어떤 종류의 타입 변환을 허용할 것인가?
새로운 타입과 다른 타입 사이의 변환을 결정한다. T1 타입의 객체를 T2 타입의 객체로 암시적(implicit)으로 변환하려면 T1 클래스에 타입 변환 함수를 만들거나 T2 클래스에 비명시 호출 생성자를 만들어야 한다. T1 타입의 객체를 T2 타입의 객체로 명시적(explicit)으로 변환하려면 변환 함수를 따로 만드는 대신, 타입 변환 함수나 비명시 호출 생성자는 만들지 말아야 한다.
- 어떤 연산자와 함수를 두어야 의미가 있는가?
클래스 안에 선언할 멤버 혹은 비멤버 함수가 여기서 결정된다.
- 표준 함수들 중에서 어떤 것을 허용하지 말 것인가?
private으로 선언해야 하는 함수가 여기에 해당된다.
- 새로운 타입의 멤버에 대한 접근 권한을 어느 쪽에 줄 것인가?
어떤 클래스 멤버를 public, protected, 그리고 private으로 선언할 것인지 결정하는 데 도움을 주는 질문이다. 또한, 프렌드로 선언해야 할 클래스와 함수, 클래스 중첩 등에 대한 결정을 내리는 데도 이 질문이 거들어 준다.
- 선언되지 않은 인터페이스로 무엇을 둘 것인가?
수행 성능, 예외 안전성, 자원 사용 등 새로 정의하는 타입에서 보장해야 할 부분은 클래스 구현에서 제약으로 작용한다.
- 새로운 타입이 얼마나 일반적인가?
새로 정의하는 타입이 동일 계열의 타입군(family of types) 전체일 수도 있다. 그렇다면 새로운 클래스 템플릿을 정의해야 한다.
- 정말로 꼭 필요한 타입인가?
기존 클래스에서 기능 몇 개가 아쉬워서 파생 클래스를 정의하고 있다면, 차라리 비멤버 함수나 템플릿을 몇 개 더 정의하는 것이 낫다.
효과적인 클래스를 정의하는 일은 어렵지만, 이 역경을 뚫고 설계된 사용자 정의 클래스는 매우 든든하고 가치 있는 타입으로 사용될 것이다.
NOTE
① 클래스 설계는 타입 설계이다. 새로운 타입을 정의하기 전에 이번 항목에 나온 고려사항을 빠짐없이 점검해보자.
'Object Oriented Programming(C++) > Effective C++' 카테고리의 다른 글
Effective C++ | 항목 21 함수에서 객체를 반환할 경우에는 참조자를 반환하려고 하지 말자 (0) | 2022.02.03 |
---|---|
Effective C++ | 항목 20 값에 의한 전달보다는 상수 객체 참조자에 의한 전달이 대개 낫다 (0) | 2022.02.03 |
Effective C++ | 항목 18 인터페이스 설계는 제대로 쓰기엔 쉽게, 엉터리로 쓰기엔 어렵게 하자 (0) | 2022.02.03 |
Effective C++ | 항목 17 new로 생성한 객체를 스마트 포인터에 저장하는 코드는 별도의 한 문장으로 만들자 (0) | 2022.01.25 |
Effective C++ | 항목 16 new와 delete를 사용할 때는 형태를 반드시 맞추자 (0) | 2022.01.25 |
댓글