일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 스마트 포인터
- operator new
- effective stl
- 오블완
- implicit conversion
- 영화
- UE4
- 루아
- 참조자
- Smart Pointer
- c++
- Effective c++
- 다형성
- 반복자
- 언리얼
- resource management class
- reference
- 게임
- 함수 객체
- 비교 함수 객체
- more effective c++
- 메타테이블
- 예외
- 티스토리챌린지
- 상속
- lua
- 영화 리뷰
- exception
- virtual function
- 암시적 변환
Archives
- Today
- Total
스토리텔링 개발자
[Effective C++] 32. public 상속은 "is-a" 본문
728x90
항목 32. public 상속 모형은 반드시 “is-a(...는 ...의 일종이다)”를 따르도록 만들자
public 상속의 의미
- 자식 클래스의 모든 객체는 부모 클래스 객체지만, 부모 클래스 객체는 자식 클래스 객체가 아니다.
- D(Derived) is a B(Base)이지만, B는 D의 일종이 아니다.
public 상속의 예 : 새 클래스와 팽귄 클래스
- 직관적으로 만들다 보면 모호한 경우가 생긴다.
- 방식 1. 펭귄을 새의 자식으로 만들었을 때
class Bird
{
public:
virtual void fly();
...
};
class Penguin : public Bird
{
// 펭귄 역시 새지만,
// fly()를 지원하는 것이 맞는가?
...
}l
- 보완하면 다음과 같이 할 수 있을 것이다.
- 방식 2. 날 수 있는 새 관련 상속 트리를 분화시킨다.
class Bird
{
... // fly 함수를 선언하지 않는다.
};
class FlyingBird : public Bird
{
public:
virtual void fly();
...
};
class Penguin : public Bird
{
// fly 함수가 없는 부모를 상속받는다.
...
};
- 허나, 비행 능력이 있는 새와 없는 새를 구분할 필요가 없는 소프트웨어의 경우 복잡도만 늘어나는 일이다.
- 최고의 설계는 제작하려는 소프트웨어 시스템이 기대하는 바에 따라 다르며, 이상적인 설계란 없다.
- 방식 3. fly 함수를 사용할 시, 런타임 에러를 발생시킨다.
class Bird
{
virtual void fly();
...
};
class Penguin : public Bird
{
// fly 사용 시 반드시 aseertion 에러
virtual void fly() { assert(false && "Attempt to make a penguin fly!"); }
};
- 문제점
- 이 방법은 "펭귄은 날 수 없다" 는 의미를 보장해주는 것이 아니다.
- "펭귄은 날 수 있으나, 실제로 날려고 하면 에러가 난다."의 의미이다.
- 컴파일 단에서는 날 수 없음을 발견할 수 없고, 런타임 시에만 발견할 수 있다.
- 이 방법은 "펭귄은 날 수 없다" 는 의미를 보장해주는 것이 아니다.
- 인터페이스 단에서 날 수 없음을 알 수 있는 편이 좋을 것이다.
class Bird
{
...
};
class Penguin : public Bird
{
...
};
// 애초에 fly 함수를 선언하지 않는 방법
Penguin p;
p.fly(); // 에러!
좀 더 미묘한 예제
- "직사각형을 상속받는 정사각형"은 개념적으로 틀릴 게 없어 보인다.
- 하지만 실제 구현으로 가면 문제가 발생한다.
// 직사각형 클래스
class Rectangle
{
public:
int height;
int width;
};
void makeBigger_Height(Rectangle& r)
{
int oldHeight = r.height;
r.width += 10;
assert(r.height == oldHeight); // height가 반드시 변할 것
}
// 정사각형 클래스
class Square : public Rectangle
{
...
}
Square s;
...
assert(s.width == s.height); // 가로 세로가 같아야 정사각형이다.
makeBigger_Height(s); // 높이만 키우는 함수에 정사각형이 들어갈 수도 있다?
assert(s.width == s.height); // 반드시 실패한다!
- 다시 한번 반복하면,
- public 상속은 기본 클래스 객체가 가진 ‘모든 것들이’ 파생 클래스 객체에도 그대로 적용된다고 단정하는 상속
- 그러므로 이 상속 트리의 경우 틀린 것이 된다.
클래스들 사이에 맺을 수 있는 관계
728x90
'개발 > Effective C++' 카테고리의 다른 글
[Effective C++] 34. 인터페이스 상속과 구현 상속의 차이 (0) | 2024.07.03 |
---|---|
[Effective C++] 33. 상속된 이름 가리기 문제 (0) | 2024.07.02 |
[Effective C++] 31. 컴파일 의존성 줄이기 (0) | 2024.06.27 |
[Effective C++] 30. 인라인 함수 (0) | 2024.06.26 |
[Effective C++] 29. 예외 안전성 (0) | 2024.06.25 |
Comments