스토리텔링 개발자

[Effective C++] 19. 클래스 설계 본문

개발/Effective C++

[Effective C++] 19. 클래스 설계

김디트 2024. 6. 12. 11:43
728x90

항목 19. 클래스 설계는 타입 설계와 똑같이 취급하자

 

 

 

좋은 타입이란?
  1. 문법(syntax)이 자연스럽다.
    • 사용 시 이질감이 없어야 한다.
  2. 의미 구조(semantics)가 직관적이다.
    • 타입의 의미가 명확해서 어떤 역할인지 한눈에 알아차릴 수 있어야 한다.
  3. 한 가지 이상 효율적인 구현이 가능하다.
  • 하지만 C++에서는 충분한 고민 없이 클래스 정의를 했다간 세 가지 중 어느 것도 달성하기 힘들다.

 

 

 

커스텀 클래스 설계 시 해야 할 질문들
  1. 객체 생성 및 소멸은 어떻게 이루어져야 하는가?
    • 클래스 생성자, 소멸자 설계에 대한 고민이다.
    • 메모리 할당 함수(operator new, operator new[], operator delete, operator delete[]) 를 재정의 할 경우 이들 설계 역시 함께 고민되어야 한다.
  2. 객체 초기화는 객체 대입과 어떻게 달라야 하는가?
    • '초기화'와 '대입'은 해당하는 함수 호출이 아예 다르므로 고민이 필요하다. (항목 4 참조)
  3. 객체가 값에 의해 전달되는 경우에 어떤 의미를 줄 것인가?
    • 어떤 타입에 대해 '값에 의한 전달' 을 구현하는 쪽은 복사 생성자이다.
  4. 적법한 값 제약(클래스의 불변 속성)은 어떤 방식으로 지킬 것인가?
    • 클래스의 불변 속성
      • 클래스 데이터 멤버의 값에 주어지는 제약.
      • 예컨대 Month 클래스의 데이터 정수 멤버는 1 ~ 12 안에서만 유효하므로 이 제약이 지켜져야 한다.
    • 클래스의 불변 속성은 클래스 차원에서 지켜줘야 한다.
    • 불변 속성을 지키기 위해서 다음 클래스 멤버 함수 안에서 에러 점검을 하게 될 것이다.
      • 생성자
      • 대입 연산자
      • setter 함수
    • 함수가 발생시키는 예외 처리 혹은 함수 예외 지정(throw, noexcept) 설계도 고려 사항이다.
  5. 기존의 클래스 상속 계통망(inheritance graph)에 맞출 것인가?
    • 이미 존재하는 클래스에서 상속을 받는다면 설계는 상위 클래스에 제약을 받는 것이 당연할 것이다.특
      • 멤버 함수가 가상 함수인지 비가상 함수인가의 여부가 중요하다. (항목 34, 항목 36 참조)
      • 특히 소멸자가 가상 함수인가는, 동적 할당 및 다형성에 큰 영향을 끼친다.
  6. 어떤 종류의 타입 변환을 허용할 것인가? (항목 15 참조)
    • 암시적(implicitly) 변환을 제공한다.
      • 암시적 변환을 지원할 타입에 대한 타입 변환 함수를 제공한다.
        • ex) T1 클래스 내에 'operator T2' 함수 제공
      • 인자 한 개로 호출될 수 있는 비명시 호출(non-explicit) 생성자를 제공한다.
        • ex) T2 클래스 내에 T1 인자를 받는 생성자 제공
    • 명시적(explicitly) 변환을 제공한다.
      • 해당 변환을 맡을 별도 이름의 함수를 만들되 암시적 변환이 될 함수들은 제공하면 안된다.
  7. 어떤 연산자와 함수를 제공할 것인가?
    • 어떤 것은 멤버 함수로 유용할테지만, 그렇지 않은 것도 있을 것이다. (항목 23, 항목 24, 항목 46 참조)
  8. 표준 함수들 중 어떤 것을 허용하지 않을 것인가?
    • 표준 함수 : 컴파일러가 알아서 생성하는 함수
    • 허용하지 않을 것이라면 private로 선언해주어야 할 것이다. (항목 6 참조)
  9. 클래스 멤버 접근권한을 어느 쪽에 줄 것인가?
    • 어떤 클래스 멤버를 public, protected, private 영역에 둘 것인가.
    • 어떤 클래스나 함수를 friend로 만들 것인가.
    • 클래스를 다른 클래스에 중첩시켜도 될 것인가.
  10. '선언되지 않은 인터페이스' 로 무엇을 둘 것인가?
    • 이 신규 타입은 어떤 종류의 것들을 보장할 것인가?
      • 수행 성능 및 예외안정성 (항목 29 참조)
      • 자원 사용 (잠금 및 동적메모리)
    • 제작자가 보장하겠다고 결정한 내용들은 클래스 구현할 때 고려해야 할 제약이 된다.
  11. 새로 만드는 타입이 얼마나 일반적인가?
    • 새로 정의하는 것이 단일 타입이 아니라 동일 계열의 타입군(family of types)일 경우.
    • 새로운 단일 클래스가 아니라 새로운 클래스 탬플릿을 정의해야 한다.
  12. 정말로 필요한 타입인가?
    • 기능 몇개가 아쉬워 파생 클래스를 만드는 것보단 간단한 비멤버 함수, 템플릿을 정의하자.
728x90
Comments