서적 정리/Effective C++

38."has-a(...는 ...를 가짐)" 혹은 "is-implemented-in-terms-of(...는 ...를 써서 구현됨)"를 모형화할 때는 객체 합성을 사용하자

민돌이2 2021. 12. 22. 01:50

합성(composition)이란 어떤 타입의 객체들이 그와 다른 타입의 객체들을 포함하고 있을 경우 그 타입들 사이의 관계를 일컫는다.

포트폴리오에 히트박스, 애니메이션, 모델 등 클래스를 모두 포함시킨 캐릭터 클래스를 생각하면 된다.

class Address{};
class PhoneNumber{};

class Person
{
private:
	string name;
	Address address;
	PhoneNumber voiceNumber;
	PhoneNumber faxNumber;
};

string, Address, PhoneNumber를 합성하여 Person 클래스를 구현하였다.

 

public 상속은 is-a(...는 ...의 일종이다)라는 의미인데, 객체 합성 역시 같은 의미를 갖는다.

실제로는 뜻을 has-a(...는 ...를 가짐) 혹은 is-implemented-in-terms-of(...는 ...를 써서 구현됨)을 뜻할 수 있다.

객체 중에는 사람, 이동수단 등 사물을 본 뜬 것들을 응용 영역(application domain)에 속하고, 응용 영역에 속하지 않는 뮤텍스, 버퍼, 탐색트리 등 나머지 것들을 구현 영역(implementaion domain)이라고 한다.

객체 합성이 응용 영역의 객체들 사이에서 일어나면 has-a 관계, 구현 영역에서 일어나면 is-implemented-in-terms-of 관계를 나타낸다.

 

위 코드에서 Person 클래스는 has-a 관계이다. 사람은 이름을 갖고있다(Person has a name), 사람은 주소를 갖고있다(Person has a address)라고 표현할 수 있다. 사람이 이름의 일종이다(Person is a name) 이라는 것은 말이 안된다.

is-a 관계와 has-a 관계의 차이를 이해할 수 있어야 한다.

 

is-a와 has-a의 차이는 이해했으면 is-implemented-in-terms-of와 is-a의 차이는 좀 햇갈릴 수 있다.

is-a(...는 ...의 일종이다)와 is-implemented-in-terms-of(...는 ...를 써서 구현됨)는 어떻게 보면 비슷하다.

 

이 책에선 표준 라이브러리의 set과 list로 상속을 비교하면서 설명하나 그냥 내가 이해한대로 적을 것이다.

맞는 비교는 아닐 수 있으나 char와 int로 비교하겠다.

char는 1byte로 int는 4byte이다. char의 범위는 28=256이므로 -128~127이고 int의 범위는 232=4,294,967,296이므로

-2,147,483,648~2,147,483,647이다.

char의 범위는 int의 범위에 포함된다고 볼 수있다. 만약 int를 public 상속받아서 char를 구현한다고 생각하면 어떻게 될까? public 상속(is-a)은 기본 클래스의 모든 것을 받아야하는데 int에는 들어올 수 있는 값이 char에는 들어올 수 없다.

200 값을 넣고 싶은데 char는 포함할 수 없으나, int는 포함할 수 있다. 그러므로 is-a관계가 될 수 없다.

그러므로 char 클래스는 int 클래스를 사용하여 구현되는 형태의 설계로 해야한다.

어거지로 코드를 짜보면

class char
{
private:
	int data;
}

여기서 char 범위에 벗어난 -129이하 128이상은 예외 처리해버리면 될 것이다.

이런 관계를 is-implemented-in-terms-of(...는 ...를 써서 구현됨)이라고 한다.

 

이것만은 잊지 말자

객체 합성(composition)의 의미는 public 상속이 가진 의미와 완전히 다르다.

응용 영역에서 객체 합성의 의미는 has-a(...는 ...를 가짐)이다.

구현 영역에서는is-implemented-in-terms-of(...는 ...를 써서 구현됨)의 의미를 갖는다.

728x90