KoreanFoodie's Study
Effective C++ | 항목 40 : 다중 상속은 심사숙고해서 사용하자 본문
C++ 프로그래머의 필독서이자 바이블인, 스콧 마이어스의 Modern Effective C++ 를 읽고 기억할 내용을 요약하고 있습니다. 꼭 읽어보시길 추천드립니다!
항목 40 : 다중 상속은 심사숙고해서 사용하자
핵심 :
1. 다중 상속은 단일 상속보다 복잡하다. 새로운 모호성 문제를 일으킬 뿐 아니라 가상 상속이 필요해질 수도 있다.
2. 가상 상속을 쓰면 크기 비용, 속도 비용이 늘어나며 초기화 및 대입 연산의 복잡도가 커진다. 따라서 가상 기본 클래스에는 데이터를 두지 않는 것이 현실적으로 가장 실용적이다.
3. 다중 상속을 적법하게 쓸 수 있는 경우가 있다. 여러 시나리오 중 하나는, 인터페이스 클래스로부터 public 상속을 시킴과 동시에 구현을 돕는 클래스로부터 private 상속을 시키는 것이다.
다중 상속으로 인해 생기는 모호성 문제의 예시 코드를 한 번 보자.
class Item
{
public:
void checkOut() {}
};
class Gadget
{
private:
void checkOut() {}
};
class MP3: public Item, public Gadget {};
int main()
{
MP3 mp;
// 에러! 어떤 함수인지 모호함(ambiguous)
mp.checkOut();
// Item 의 checkOut
mp.Item::checkOut();
// 에러! private 임
mp.Gadget::checkOut();
}
접근 지정자가 다르더라도, 최적 일치 함수를 찾는 것이 먼저이므로, 모호성 에러가 발생한다.
"죽음의 MI(multiple inheritance) 마름모꼴" 문제도 있다.
class File { ... };
class InputFile: public File { ... };
class OutputFile: public File { ... };
class IOFile: public InputFile, public OutputFile { ... };
이렇게 되면, IOFile 클래스는 File 클래스의 경로 갯수 만큼의 File 객체를 가지게 된다. 가상 상속(virtual inheritance) 를 사용하면, 위와 같은 데이터 멤버의 중복 생성을 막을 수 있다.
class File { ... };
class InputFile: virtual public File { ... };
class OutputFile: virtual public File { ... };
class IOFile: public InputFile, public OutputFile { ... };
하지만 가상 상속은 느리고 비싸다. 그러므로 웬만하면 피하는 것이 좋다.
MI 도 마찬가지로 단점이 많다고 알려진 방식이지만, 다음 예시를 보면서 MI 를 사용했을 때 이득을 볼 수 있는 시나리오를 하나 익혀두도록 하자. 인터페이스 클래스로부터 public 상속을 시킴과 동시에 구현을 돕는 클래스로부터 private 상속을 시키는 케이스를 볼 것이다.
class IPerson
{
public:
virtual ~IPerson();
virtual std::string name() const = 0;
virtual std::string birthDate() const = 0;
};
class DatabaseID { ... };
class PersonInfo
{
public:
explicit PersonInfo(DatabaseID pid);
virtual ~PersonInfo();
virtual const char* theName() const;
virtual const char* theBirthDate() const;
virtual const char* valueDelimOpen() const;
virtual const char* valueDelimClose() const;
};
// 다중 상속 사용
class CPerson: public IPerson, private PersonInfo
{
public:
explicit CPerson(DatabaseID pid) : PersonInfo(pid) {}
virtual std::string name() const
{
return PersonInfo::theName();
}
virtual std::string birthDate() const
{
return PersonInfo::theBirthDate();
}
private:
// 가상 함수들에 대한 재정의 버전을 만듦 (private 상속의 이점)
// 객체 합성의 경우, 가상 함수의 재정의를 못하는 설계\
const char* valueDelimOpen() const { return ""; }
const char* valueDelimClose() const { return ""; }
};
'Tutorials > C++ : Advanced' 카테고리의 다른 글
Comments