Notice
Recent Posts
Recent Comments
Link
«   2026/05   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
Archives
Today
Total
관리 메뉴

로또

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

책/Effective C++

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

아롱로또 2023. 11. 15. 13:26

다루는 내용

클래스를 설계할 때는 언어 설계자가 그 언어의 기본제공 타입을 설계하는 것과 같은 정성이 필요하다.

효과적인 클래스를 설계할 때 고려사항에 대해 알아보자.

 

아직까지 와닿지 않거나 이해가 가지 않는 내용이 많다. 추후 클래스를 설계할 일이 있을 때 다시 보자.

효과적인 클래스를 위한 고려사항

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

1에 따라서 클래스 생성자 및 소멸자의 설계가 바뀐다. 뿐만 아니라 메모리 할당 함수(new, delete, new[], delete[])를 직접 작성할 경우에는 이들 함수의 설계에도 영향을 미친다.

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

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

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

이 때 중요한 포인트는 어떤 타입에 대해 '값에 의한 전달'을 구현하는 쪽은 복사 생성자라는 것이다. 기억해두자.

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

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

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

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

이미 존재하는 클래스로부터 상속을 시킨다고 하면, 우리의 설계는 이들 클래스에 의해 제약을 받게 된다. 특히, 멤버 함수가 가상인지 비가상인지의 여부는 큰 영향을 끼칠 것이다. 우리가 만든 클래스를 다른 클래스들이 상속할 수 있게 만들자고 결정했다면 이에 따라 멤버 함수의 가상 함수 여부가 결정된다. 특히 소멸자는 더욱 그렇다. (7. 다형성을 가진 기본 클래스에서는 반드시 소멸자를 가상 소멸자로 선언하자.)

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

우리가 만든 타입은 결국 기존의 수많은 타입과 어울려 사용되어야 한다.

T1 타입의 객체를 T2 타입의 객체로 암시적으로 변환하고 싶다면, T1 클래스에 타입 변환 함수(operator T2)를 추가하거나 인자 한 개로 호출될 수 있는 비명시호출(non-explicit) 생성자를 T2 클래스에 넣어두어야 할 것이다.

명시적 타입 변환만 허용하고 싶다면 해당 변환을 담당하는 별도 이름의 함수를 만들되, 타입 변환 연산자나 비명시호출 생성자를 만들어서는 안된다.

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

우리가 만든 클래스 안에 선언할 함수를 결정하자. 어떤 함수는 멤버 함수로 적당할 것이고, 어떤 함수는 그렇지 않을 것이다.

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

private으로 선언해야 하는 함수를 결정하자.

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

어떤 클래스 멤버를 public, protected, private 영역에 둘 것인가를 결정하는데 도움을 줄 수 있을 것이다.

또한 friend로 만들어야 할 클래스 및 함수를 정하는 것은 물론이고 한 클래스를 다른 클래스에 중첩시켜도 되는가에 대한 결정을 내리는 데도 도움을 줄 것이다.

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

우리가 만들 타입이 제공할 보장이 어떤 종류일까에 대한 질문으로, 보장할 수 있는 부분은 수행 성능 및 예외 안전성, 그리고 자원 사용(lock 및 동적 메모리 등)이 있다. 이들에 대해 우리가 보장하겠다고 결정한 결과는 클래스 구현에 있어서 제약으로 작용하게 될 것이다.

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

우리가 만드는 타입이 동일 계열의 타입군(family of types) 전체일지도 모른다. 진짜 그렇다면 우리가 원하는 것은 새로운 클래스가 아니다. 우리는 새로운 클래스 템플릿을 정의해야 할 것이다.

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

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

 

이것만은 잊지 말자!

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