[C++] 항목 38: “has-a(…는…를 가짐)” 혹은 “is-implemented-in-terms-of(…는…를 써서 구현됨)”를 모형화할 때는 객체 합성을 사용하자

업데이트:     Updated:

카테고리:

태그:

이 글은 아래의 책을 자세히 정리한 후, 정리한 글을 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> { ... }

논리적 모순:

  1. set은 list의 일종이다 (상속 관계가 주장하는 것)
  2. list는 중복 원소를 가질 수 있는 컨테이너이다
  3. 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를 써서 구현된다”가 적절할 때
  • 기본 클래스의 일부 특성만 필요하거나, 다른 의미로 사용될 때

🧐 정리

  1. 객체 합성(composition)의 의미는 public 상속이 가진 의미와 완전히 다르다.
  2. 응용 영역에서 객체 합성의 의미는 has-a(…는 …를 가짐)이다.
    일상 사물을 본뜬 객체들 사이의 관계를 표현할 때 사용한다.
  3. 구현 영역에서 객체 합성의 의미는 is-implemented-in-terms-of(…는 …를 써서 구현됨)이다.
    시스템 구현을 위한 인공물들 사이의 관계를 표현할 때 사용한다.
  4. is-a 관계가 성립하지 않는다면 public 상속 대신 객체 합성을 사용하자.
    Set과 list의 예처럼, 논리적으로 맞지 않는 상속은 피해야 한다.

Cpp 카테고리 내 다른 글 보러가기

댓글남기기