방프리
17.12.12. Effective C++ 6. 상속, 그리고 객체 지향 설계 (항목32) 본문
항목 32 : public 상속 모형은 반드시 "is-a(...는 ...의 일종이다)"를 따르도록 만들자
객체 지향 OOP의 3대 요소 중 하나인 상속!! 짚고 넘어가지 않을 수 없는데요.
책에서도 다른 건 다 까먹어도 되지만 이 항목만큼은 항상 기억하고 넘어가야 한다고
강조하고 있습니다. 그만큼 중요하다는 뜻이겠죠?
일반적으로 public 상속은 "...는 ...의 일종이다~" 라고 정의할 때 사용합니다.
이해가 잘 안되시죠? 차근차근 예를 들어서 살펴보겠습니다.
간단한 몬스터를 생성하는 클래스를 통해 알아보겠습니다.
ex1)
class cMonster
{
//do Something
};//몬스터 모두를 지징하는 클래스
class cGoblin : public cMonster
{
//do Something
};// 고블린 몬스터를 지칭하는 클래스
몬스터는 고블린이 될 수 있습니다. 하지만 고블린은 몬스터가 될 수 없죠 무슨 말인지 잘 모르겠다구요?
몬스터를 지칭하면 고블린도 몬스터이기 때문에 고블린은 몬스터의 일종이다~ 라고 할 수 있습니다.
하지만 몬스터는 고블린의 일종이다~ 이상하지 않나요? 고블린보다 몬스터가 더 큰 개념이기 때문이죠
그런고로 책에서 다음과 같이 정리하였습니다.
(1) D(Derived) 타입으로 만들어진 모든 객체는 또한 B(Base) 타입의 객체이지만, 그 반대는 되지 않음
(2) B 타입의 객체가 쓰일 수 있는 곳에는 D 타입의 객체도 마찬가지로 쓰일 수 있다고 단정
(3) D 타입이 필요한 부분에 B 타입의 객체를 쓰는 것은 불가능
(4) 모든 D는 B의 일종이지만, B는 D의 일종이 아님
(5) C++는 public 상속을 이렇게 해석하도록 문법적으로 지원
But.... 항상 예외는 존재하는 법...(괜히 예외처리가 있는게 아니죠~)
예를 보면서 설명드리겠습니다. 일단 새에 관한 클래스를 만들어보겠습니다.
ex2)
class cBird
{
public:
virtual void Fly(); //새는 날 수 있으니깐
};
그리고 타조에 관한 클래스를 만들어보겠습니다.
ex3)
class cOstrich : public cBird
{
public:
void Fly(); //무슨 소리 입니까? 타조는 못날아요!!
};
네.... 이딴 거지같은 함정이 생겨버리고 맙니다. (왜 상속을 했는데 쓰질 못하니...ㅜㅜ)
결국 몇 가지 클래스를 더 거쳐 만들 수 밖에 없죠...
ex4)
class cFlyingBird : public cBird
{
public:
virtual void Fly();
//do Something
};
class cOstrich : public cFlyingBird
{
//do Something
};
다른 방법도 존재하긴 합니다. Fly 함수를 재정의해서 런타임 에러를 발생시키는 것이죠
필자는 여기서 끝나지 않고 하나의 예를 더 사용하여 우리에게 경고를 보여줍니다.
Sqare(정사각형) 클래스는 Rectangle(직사각형) 클래스로부터 상속을 받아야 하는가?
ex5)
class cRectangle
{
public:
virtual void setHeight(int newHeight);
virtual void setWidth(int newWidth);
virtual int height() const;
virtual int width() const;
};
void makeBigger(Rectangle& r) // 사각형의 넓이를 늘리는 함수
{
int oldHeight = r.height();
r.setWidth(r.width() + 10 ); //r의 가로길이에 10을 더함
assert(r.height() == oldHeight); //r의 세로 길이가 변하지 않는다는 조건에 assert를 걸어둠
}
class cSquare : public cRectangle()
{
//do Something
};
int main(void)
{
Square s;
assert(s.width() == s.height()); //모든 정사각형은 모든 변의 길이가 같아야겠죠?
makeBigger(s); //사각형의 넓이를 늘립니다. 정사각형이요!!
assert(s.width() == s.height()); //마찬가지로 조건을 걸어둡니다.
}
와....극혐이네요... 직사각형의 속성을 받으니 정사각형의 역할을 제대로 하질 못합니다.
필자는 이 예를 보여주면서 연관되지 않은 속성끼리 억지로 연관시켰다가는 이런 참사를
불어온다는 것을 몸소 보여줍니다. 가장 많이 사용하는 프로그래밍 기법으로써 꼭꼭!!
알고 넘어가야할 것 같습니다.
(참고로 이런 상속 기법은 메모리 낭비와 구조 설계에 굉장히 복잡하기 때문에 지금은 거의 사용되지
않습니다. 그럼 현재 뭐가 쓰이냐? 유니티나 언리얼 엔진만 봐도 답이 나오지 않나요?)
이것만은 잊지 말자!
* public 상속의 의미는 "is-a(...는 ...의 일종)"입니다. 기본 클래스에 적용되는 모든 것들이 파생 클래스에
그대로 적용되어야 합니다. 왜냐하면 모든 파생 클래스 객체는 기본 클래스 객체의 일종이기 때문입니다.
'C++ > Effective C++' 카테고리의 다른 글
17.12.23. Effective C++ 6. 상속, 그리고 객체 지향 설계 (항목34) (0) | 2020.01.17 |
---|---|
17.12.15. Effective C++ 6. 상속, 그리고 객체 지향 설계 (항목33) (0) | 2020.01.17 |
17.12.11. Effective C++ 5. 구현 (항목31) (0) | 2020.01.17 |
17.12.05. Effective C++ 5. 구현 (항목30) (0) | 2020.01.15 |
17.11.30. Effective C++ 5. 구현 (항목29) (0) | 2020.01.15 |