득이공간
[Effective C++] 4장. 설계 및 선언 본문
해당 게시물은 프로텍 미디어의 'Effective C++'를 읽고
학습한 내용을 개인적으로 요약한 글입니다.
📌 목차 - 4장. 설계 및 선언
4-1. 인터페이스 설계는 제대로 쓰기엔 쉽게, 엉터리로 쓰기엔 어렵게 하자
4-2. 클래스 설계는 타입 설계와 똑같이 취급하자
4-3. ‘값에 의한 전달’ 보다는 ‘상수객체 참조자에 의한 전달’ 방식을 택하는 편이 대개 낫다
4-4. 함수에서 객체를 반환해야 할 경우에 참조자를 반환하려고 들지 말자
4-5. 데이터 멤버가 선언될 곳은 private 영역임을 명심하자
4-6. 멤버 함수보다는 비멤버 비프렌드 함수와 더 가까워지자
4-7. 타입 변환이 모든 매개변수에 대해 적용되어야 한다면 비멤버 함수를 선언하자
4-8. 예외를 던지지 않는 swap에 대한 지원도 생각해 보자
📌 4-1. 인터페이스 설계는 제대로 쓰기엔 쉽게, 엉터리로 쓰기엔 어렵게 하자
- 좋은 인터페이스는 제대로 쓰기에 쉬우며 엉터리로 쓰기에 어렵다. 인터페이스를 만들 때는 이 특성을 지닐 수 있도록 고민하고 또 고민하자.
- 인터페이스의 올바른 사용을 이끄는 방법으로는 인터페이스 사이의 일관성 잡아주기, 그리고 기본제공 타입과의 동작 호환성 유지하기가 있다.
- 사용자의 실수를 방지하는 방법으로는 새로운 타입 만들기, 타입에 대한 연산을 제한하기, 객체의 값에 대해 제약 걸기, 자원 관리 작업을 사용자 책임으로 놓지 않기가 있다.
- tr1::shared_ptr는 사용자 정의 삭제자를 지원한다. 이 특징 때문에 tr1::shared_ptr는 교차 DLL 문제를 막아주며, 뮤텍스 등을 자동으로 잠금 해제하는 데 쓸 수 있다.
📌 4-2. 클래스 설계는 타입 설계와 똑같이 취급하자
- 클래스 설계는 타입 설계다. 새로운 타입을 정의하기 전에, 다음 고려사항을 모두 점검하자.
- 새로 정의한 타입의 객체 생성 및 소멸은 어떻게 이루어져야 하는가?
- 객체 초기화는 객체 대입과 어떻게 달라야 하는가?
- 새로운 타입으로 만든 객체가 값에 의해 전달되는 경우에 어떤 의미를 줄 것인가?
- 새로운 타입이 가질 수 있는 적법한 값에 대한 제약은 무엇으로 잡을 것인가?
- 기존의 클래스 상속 계통망(inheritance graph)에 맞출 것인가?
- 어떤 종류의 타입 변환을 허용할 것인가?
- 어떤 연산자와 함수를 두어야 의미가 있을까?
- 표준 함수들 중 어떤 것을 허용하지 말 것인가?
- 새로운 타입의 멤버에 대한 접근권한을 어느 쪽에 줄 것인가?
- ‘선언되지 않은 인터페이스’로 무엇을 둘 것인가?
- 새로 만드는 타입이 얼마나 일반적인가?
- 정말로 꼭 필요한 타입인가?
📌 4-3. ‘값에 의한 전달’ 보다는 ‘상수객체 참조자에 의한 전달’ 방식을 택하는 편이 대개 낫다
- ‘값에 의한 전달’보다는 ‘상수 객체 참조자에 의한 전달’을 선호하자. 대체적으로 효율적일 뿐만 아니라 복사손실 문제까지 막아 준다.
- 하지만 기본제공 타입 및 STL 반복자, 그리고 함수 객체 타입에 대해서는 ‘값에 의한 전달’이 더 적절하다.
📌 4-4. 함수에서 객체를 반환해야 할 경우에 참조자를 반환하려고 들지 말자
- 지역 스택 객체에 대한 포인터나 참조자를 반환하는 일, 혹은 힙에 할당된 객체에 대한 참조자를 반환하는 일, 또는 지역 정적 객체에 대한 포인터나 참조자를 반환하는 일은 그런 객체가 두 개 이상 필요해질 가능성이 있다면 절대로 하지 말자.
📌 4-5. 데이터 멤버가 선언될 곳은 private 영역임을 명심하자
- 데이터 멤버는 private 멤버로 선언하자. 이를 통해 클래스 제작자는 문법적으로 일관성 있는 데이터 접근 통로를 제공할 수 있고, 필요에 따라서는 세밀한 접근 제어도 가능하며, 클래스의 불변속성을 강화할 수 있을 뿐 아니라, 내부 구현의 융통성도 발휘할 수 있다.
- protected는 public보다 더 많이 ‘보호’받고 있는 것이 절대로 아니다.
📌 4-6. 멤버 함수보다는 비멤버 비프렌드 함수와 더 가까워지자
- 멤버 함수보다는 비멤버 비프렌드 함수를 자주 쓰도록 하자. 캡슐화 정도가 높아지고, 패키징 유연성도 커지며, 기능적인 확장성도 늘어난다.
📌 4-7. 타입 변환이 모든 매개변수에 대해 적용되어야 한다면 비멤버 함수를 선언하자
- 어떤 함수에 들어가는 모든 매개변수(this 포인터가 가리키는 객체도 포함해서)에 대해 타입 변환을 해 줄 필요가 있다면, 그 함수는 비멤버이어야 한다.
📌 4-8. 예외를 던지지 않는 swap에 대한 지원도 생각해 보자
- std::swap이 우리가 정의한 타입에 대해 느리게 동작할 여지가 있다면 swap 멤버 함수를 제공하자. 이 멤버 swap은 예외를 던지지 않도록 만들자.
- 멤버 swap을 제공했으면, 이 멤버를 호출하는 비멤버 swap도 제공하자. 클래스(템플릿이 아닌)에 대해서는, std::swap도 특수화해 두자.
- 사용자 입장에서 swap을 호출할 때는, std::swap에 대한 using 선언을 넣어 준 후에 네임스페이스 한정 없이 swap을 호출하자.
- 사용자 정의 타입에 대한 std 템플릿을 완전 특수화하는 것은 가능하다. 그러나 std에 어떤 것이라도 새로 ‘추가’하려고 들지는 말자.
'PS > C++' 카테고리의 다른 글
[Effective C++] 6장. 상속, 그리고 객체 지향 설계 (0) | 2025.03.27 |
---|---|
[Effective C++] 5장. 구현 (1) | 2025.03.18 |
[Effective C++] 3장. 자원 관리 (0) | 2024.11.27 |
[Effective C++] 2장. 생성자, 소멸자 및 대입 연산자 (0) | 2024.11.02 |
[Effective C++] 1장. C++에 왔으면 C++의 법을 따릅시다 (1) | 2024.10.21 |