티스토리 뷰

728x90

상속 모형은 반드시 "is-a"

• 클래스 D(Derived)를 클래스 B(Base)로부터 public 상속을 통해 파생시켰다

• D 타입으로 만들어진 모든 객체는 또한 B 타입의 객체이지만, 그 반대는 되지 않음

• B 타입의 객체가 쓰일 수 있는 곳에는 D 타입의 객체도 마찬가지로 쓰일 수 있다고 단정

• D 타입이 필요한 부분에 B 타입의 객체를 쓰는 것은 불가능

• 모든 D는 B의 일종이지만, B는 D의 일종이 아님

• C++public 상속을 이렇게 해석하도록 문법적으로 지원

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Person {...};
 
class Student: public Person {...};
 
// 모든 학생은 사람이지만 모든 사람이 학생은 아님
 
void eat(const Person& p);   // 먹는 것은 누구든 함
void study(const Student& s);   // 학과 공부는 학생만 함
 
void main()
{
    Person p;   // p는 Person의 일종(사람도 사람이니까)
    Student s;   // s는 Student의 일종(학생도 학생이니까)
    eat(p);   // 문제없음. p는 Person.
    eat(s);   // 문제없음. s는 Student이고, Student는 Person의 일종
    study(s);   // 좋음
    study(p);   // 에러, p는 Student가 아님
}
 
cs

 

public 상속과 is-a 관계가 똑같은 뜻이라는 직관 때문에 잘못 판단하는 경우가 있음

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
//-----------------------------------------------------------------------------------------
//펭귄은 새의 일종, 새는 날 수 있음
class Bird 
{
public:
    virtual void fly();   // 새는 날 수 있음
};
 
class Penguin: public Bird // 펭귄은 새임
{   
    //...
};
//위의 클래스 상으로는 펭귄은 날 수 있음
 
//-----------------------------------------------------------------------------------------
//날지 않는 새 종류도 있다는 점을 추가
class Bird {...};
 
class FlyingBird: public Bird 
{
public:
    virtual void fly();
};
 
class Penguin: public Bird 
{
    //... 
};
 
//-----------------------------------------------------------------------------------------
//다른 방법
//펭귄의 fly 함수를 재정의해서 런타임 에러를 내도록 하는 것
void error(const std::string& msg);   // 어딘가에 정의되어 있을 것임
 
class Penguin: public Brid 
{
public:
    virtual void fly() 
    {
         error("Attempt to make a penguin fly!"); 
    }
}
//위 경우는 펭귄은 날 수 없다가 아닌 펭귄은 날 수 있지만 날려고 하면 에러가 난다임
//"펭귄은 날 수 없다 - 도장 꽝" 제약사항 추가
 
class Bird 
{
    // fly 함수가 선언되지 않았음
};
 
class Penguin: public Bird 
{
// fly 함수가 선언되지 않았음
};
 
void main()
{
    Penguin p;
    p.fly();   // error
}
 
 
//-----------------------------------------------------------------------------------------
//Sqare(정사각형) 클래스는 Rectangle(직사각형) 클래스로부터 상속을 받아야 하는가?
//학교에서만 맞는 말임
 
class Rectangle 
{
public:
    virtual void setHeight(int newHeight);
    virtual void setWidth(int newWidth);
    virtual int height() const;   // 현재의 값을 반환
    virtual int width() const;
};
 
void makeBigger(Rectangle& r)   // r의 넓이를 늘리는 함수
{
    int oldHeight = r.height();
    r.setWidth(r.width()+10);   // r의 가로 길이에 10을 더함
    assert(r.height() == oldHeight);   // r의 세로 길이가 변하지 않는다는 조건에 단정문을 걸어둠
}
 
//-----------------------------------------------------------------------------------------
//public 상속을 써서 정사각형을 직사각형처럼 처리하게 허용하는 코드
class Square: public Rectangle 
{
    //...
};
 
void main()
{
    Square s;
    assert(s.width() == s.height());   // 이 단정문은 모든 정사각형에 대해서 참이어야 함
    makeBigger(s);   // 상속된 것이므로 s는 Rectangle의 일종임, s의 넓이를 늘릴 수 있음
    assert(s.width() == s.hegith());   // 이 단정문이 모든 정사각형에 대해 참이어야 함
}
 
//-----------------------------------------------------------------------------------------
// 문제 발생
• makeBigger 함수를 호출하기 전에, s의 세로 길이와 가로 길이는 동일해야함
• makeBigger 함수가 실행되는 중에, s의 가로 길이는 변하는데 세로 길이는 안변해야 함
• makeBigger 함수가 복귀한 후에, s의 세로 길이와 가로 길이는 동일해야 함
• 결국 상속 받도록 만들면 안됨
• is-a 관계가 아닌 것들을 is-a 관계로 모형화 하면 설계가 이상하게 꼬임
 
 
cs

 

총평

기본 클래스 적용되는 모든 것은 파생 클래스에 공통적이어야 합니다.

파생 클래스는 기본 클래스 객체의 일종이기 때문입니다.

반응형
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/11   »
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
글 보관함
250x250