[C++] 항목 38: “has-a(…는…를 가짐)” 혹은 “is-implemented-in-terms-of(…는…를 써서 구현됨)”를 모형화할 때는 객체 합성을 사용하자
카테고리: Cpp
태그: Cpp
이 글은 아래의 책을 자세히 정리한 후, 정리한 글을 GPT에게 요약을 요청하여 작성되었습니다.
이펙티브 C++ 제3판, 스콧 마이어스 저자, 곽용재 번역
📦 6. 상속, 그리고 객체 지향 설계
👉🏻 항목 38: “has-a(…는…를 가짐)” 혹은 “is-implemented-in-terms-of(…는…를 써서 구현됨)”를 모형화할 때는 객체 합성을 사용하자
✅ 객체 합성(Composition)이란?
has-a 관계 예제:
class Address { ... };
class PhoneNumber { ... };
class Person {
public:
...
private:
string name;
Address address;
PhoneNumber voiceNumber;
PhoneNumber faxNumber;
};
클래스 관계를 표현하는 방법:
- public 상속
→is-a(…는 …의 일종이다) - 객체 합성(composition)
→has-a(…는 …를 가짐)또는is-implemented-in-terms-of(…는 …를 써서 구현됨)
핵심:
이 예제는 has-a 관계이다.
사람은 주소와 전화번호를 가지는 것이지, 주소와 전화번호의 일종인 것이 아님!
📌 객체 합성의 두 가지 의미
객체 합성이 사용되는 영역에 따라 의미가 달라진다:
1. 응용 영역(Application Domain)에서의 객체 합성
has-a 관계
- 응용 영역: 일상에서 볼 수 있는 사물을 본뜬 객체
- 예시: 사람, 이동 수단, 주소, 전화번호
- 의미: “has-a(…는 …를 가짐)” 관계
2. 구현 영역(Implementation Domain)에서의 객체 합성
is-implemented-in-terms-of 관계
- 구현 영역: 시스템 구현을 위한 순수한 인공물
- 예시: 버퍼, 뮤텍스, 탐색 트리
- 의미: “is-implemented-in-terms-of(…는 …를 써서 구현됨)” 관계
✅ is-implemented-in-terms-of 관계 예제
list를 활용하여 set을 구현하는 예제:
template<class T>
class Set {
public:
bool member(const T& item) const;
void insert(const T& item);
void remove(const T& item);
size_t size() const;
private:
list<T> rep; // set 데이터 내부 표현부
};
template<typename T>
bool Set<T>::member(const T& item) const { ... }
template<typename T>
void Set<T>::insert(const T& item) { ... }
template<typename T>
void Set<T>::remove(const T& item) { ... }
template<typename T>
size_t Set<T>::size() const { ... }
핵심:
- list를 활용하여 set을 만드는 예제이다
- 객체 합성이 구현 영역에서 일어나기에
is-implemented-in-terms-of관계와 알맞다
❌ 잘못된 접근: public 상속 사용
만약, is-a 관계로 만들려고 하면 어떻게 될까?
template<typename T>
class Set : public list<T> { ... }
논리적 모순:
- set은 list의 일종이다 (상속 관계가 주장하는 것)
- list는 중복 원소를 가질 수 있는 컨테이너이다
- set은 중복 원소를 가질 수 없는 컨테이너이다
결론:
set은 list의 일종이 아니다. is-a 관계가 아니므로, public 상속으로 하면 안 된다.
📊 관계 유형별 구현 방법 정리
| 관계 유형 | 의미 | 구현 방법 | 사용 영역 | 예시 |
|---|---|---|---|---|
| is-a | …는 …의 일종 | public 상속 | - | Student is-a Person |
| has-a | …는 …를 가짐 | 객체 합성 | 응용 영역 | Person has-a Address |
| is-implemented-in-terms-of | …는 …를 써서 구현됨 | 객체 합성 | 구현 영역 | Set is-implemented-in-terms-of list |
💡 올바른 관계 선택 가이드
public 상속을 사용해야 할 때:
- “A는 B의 일종이다”라는 문장이 자연스럽고 논리적으로 맞을 때
- 기본 클래스의 모든 특성이 파생 클래스에도 적용될 때
객체 합성을 사용해야 할 때:
- 응용 영역: “A는 B를 가진다”가 자연스러울 때
- 구현 영역: “A는 B를 써서 구현된다”가 적절할 때
- 기본 클래스의 일부 특성만 필요하거나, 다른 의미로 사용될 때
🧐 정리
- 객체 합성(composition)의 의미는 public 상속이 가진 의미와 완전히 다르다.
- 응용 영역에서 객체 합성의 의미는 has-a(…는 …를 가짐)이다.
일상 사물을 본뜬 객체들 사이의 관계를 표현할 때 사용한다. - 구현 영역에서 객체 합성의 의미는 is-implemented-in-terms-of(…는 …를 써서 구현됨)이다.
시스템 구현을 위한 인공물들 사이의 관계를 표현할 때 사용한다. - is-a 관계가 성립하지 않는다면 public 상속 대신 객체 합성을 사용하자.
Set과 list의 예처럼, 논리적으로 맞지 않는 상속은 피해야 한다.
댓글남기기