Post List

2015년 1월 4일 일요일

다중 상속은 심사숙고해서 사용하자.

 다중 상속을 하면 둘 이상의 기본 클레스로부터 똑같은 이름(변수, 함수, typedef 등)을 물려받을 가능성이 생겨 버린다. 이럴 경우 기본클레스의 이름을 사용하여 직접 지정해줘야 한다.

 죽음의 MI 마름모꼴(deadly MI diamond)라는 좋지 않은 모양이 나올 수도 있다. 하나의 기본 클래스에서 파생된 2개의 클래스가 있고 이 2개의 클레스를 하나의 클래스가 다중상속하는 경우를 말한다. 기본 클래스의 데이터 맴버가 경로 개수만큼 중복 생성되는 경우를 말하는 것인데, 진짜 알고도 이렇게 구현했어 ? 라는 의혹을 피해 가지 못한다.

class File {...};
class InputFile : public File { ... };
class OutputFile : public File { ... };
class IOFile : public InputFile,
               public OutputFile { ... };

 만약 데이터 멤버의 중복생성을 원하는 것이 아니라면, 가상 상속을 사용해야 한다.

class File {...};
class InputFile : virtual public File { ... };
class OutputFile : virtual public File { ... };
class IOFile : public InputFile,
               public OutputFile { ... };


 하지만 한가지만 명심히자. 가상 상속을 사용하는 클래스의 객체는 일반적으로 더 크다. 가상 기본 클래스의 데이터 맴버에 접근하는 속도도 더 느리다. 한마디로 가상 상속은 비싸다.

 구태여 쓸 필요가 없다면 가상 상속은 쓰지말자. 가상 상속을 정말 쓰지 않으면 안 될 상황이라면, 가상 기본 클래스에 데이터를 넣지 않는 쪽으로 최대한 신경써라. (참고로 Java와 C#의 Interface는 데이터를 아에 갖지 못한다.)

 다중 상속도 유용하게 쓰이는 경우가 있긴 있다.
 Interface를 public으로 상속받아 구현하데, 거기에 필요한 구현들이 다른 클래스를 private로 상속받아서 쉽게 구현 될 경우가 그러하다.

class IPerson { // Interface Class
public:
  virtual ~IPerson();
  virtual std::string name() const = 0;
  virtual std::string birthDate() const = 0;
};

class PersonInfo { // 구현을 도와줄수 있는 Class
public:
  explicit Personinfo(DatabaseID pid);
  virtual ~PersonInfo();
  virtual const char * theName() const;
  virtual char * theBirthDate() const;
private:
  virtual const char* valueDelimOpen() const { return "["; }
  virtual const char* valueDelimClose() const { return "]"; }
};

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:
  const char* valueDelimOpen() const { return ""; }
  const char* valueDelimClose() const { return ""; }
};

 * 다중 상속은 단일 상속보다 확실히 복잡합니다. 새로운 모호성 문제를 일으킬 뿐만 아니라 가상 상속이 필요해질 수도 있습니다.

 * 가상 상속을 쓰면 크기 비용, 속도 비용이 늘어나며, 초기화 및 대입 연산의 복잡도가 커집니다. 따라서 가상 기본 클래스에는 데이터를 두지 않는 것이 현실적으로 가장 실용적입니다.

 * 다중 상속을 적법하게 쓸 수 있는 경우가 있습니다. 여러 시나리오 중 하나는, 인터페이스 클래스로부터 public 상속을 시킴과 동시에 구현을 돕는 클래스로부터 private 상속을 시키는 것입니다.

댓글 없음:

댓글 쓰기