[Effective C++] #32_Public 상속
Scott Meyers의 "Effective C++" 를 통해, C++ 구현에 필요한 개념들을 이해하고, 기록하기 위함입니다. 해당 항목은 6장 '상속 그리고 객체 지향 설계', 항목 32 "Public 상속 모델은 반드시 ~는~의 일종이다"에 해당하는 내용입니다.
Public 상속의 의미
class Person {...};
class Student: public Person {...};
"Public 상속은 is-a(...는...의 일종이다)" 클래스 B를 클래스 A로부터 public 상속을 통해 파생시켰다면, B 타입으로 만들어진 모든 객체는 또한 A 타입의 객체이지만, A 타입으로 생성된 모든 객체는 B 타입의 객체가 아닙니다! 쌍방 관계가 성립될 수 없죠. 따라서, A는 B보다 더 일반적인 개념이며, B는 A보다 더 특수한 개념을 나타냅니다. 쉽게 예를 들면, 모든 학생은(B 타입) 모두 사람(A 타입)이지만, 모든 사람은(A 타입) 학생(B타입)이 아닙니다!
1. Public 상속 예제: 새 그리고 펭귄
class Bird {
public:
virtual void fly;
...
};
class Penguin: public Bird {
...
}
새는 날 수 있습니다. 펭귄은 새의 일종입니다. 하지만, 위 코드 내용을 살펴보면, '모든 새는 날 수 있다, 그래서 새의 일종인 '펭귄' 또한 날 수 있다'로 해석됩니다. 하지만, 사실은 그렇지 않죠. 코드를 수정해 보겠습니다.
void error(const std::string& msg);
class Penguin: public Bird {
public:
virtual void fly() {error ("Attempt to make a penguin fly!");}
...
};
위 코드의 경우, "펭귄은 날 수 없다"로 해석되기 보다, "펭귄은 날 수 있다", 그러나 펭귄이 실제로 날려고 하면 에러가 난다"로 보입니다. 이러한 규칙 위반은 프로그램 실행 중에 발견 할 수 있는 에러로, 유효하지 않은 코드를 컴파일 단계에서 막아 줄 수 없겠죠. 따라서 아래처럼 수정합니다.
class Bird {
... //fly 함수가 없습니다.
};
class Penguin: public Bird {
... //역시 fly 함수가 없습니다
};
Penguin p;
p.fly(); //에러 발생!!
위 코드처럼 수정한 결과는, 컴파일 단계에서 유효하지 않은 코드를 막아 줄 수 있게됩니다.
1. Public 상속 예제: 직사각형 그리고 정사각형
class Rectangle {
public:
virtual void setHeight(int newHeight);
virtual void setWidth(int newWidth);
virtual int hegith () const;
virtual int width () const;
...
};
void makeBigger(Rectangle& r){
int oldHeight = r.height();
r.setWidth(r.width() + 10); //가로 길이에 10을 더합니다.
assert(r.height() == oldHeight); //직사각형 r의 세로길이는 절대 안변합니다.
}
class Square: public Rectangle {...}; // 직사각형 클래스를 상속받은 정사각형 클래스
Square s;
...
assert(s.width() == s.height()); //해당 조건문에 무조건 참이어야 합니다.
makeBigger(s); //makeBigger 함수를 통해 s의 넓이를 넓힙니다.
assert(s.width() == s.height()); //해당 조건문이 무조건 참이어야 합니다.
위 코드에서 "makeBigger" 함수는 "r"객체의 가로 길이만 변경합니다. 아래 assert를 이용한 조건문 2개는 무슨 일이 있어도 참이어합니다. 더불어, "직사각형" 클래스를 상속받은 "정사각형" 클래스는 "makeBigger" 함수를 호출 할 수 있습니다. makeBigger 함수는 Rectangle 객체에 대한 참조자를 인자로 받기 때문이죠. 하지만, 말이 안되죠. 정사각형은 넓이 혹은 높이 중 한쪽만 길어져도, 더이상 정사각형이 아닌 직사각형이 되버리기 때문입니다. Public 상속은 우리가 배웠던 "정사각형 -> 직사각형, 정사각형은 직사각형의 일종이다"의 개념이 성립되지 않습니다. 따라서, 정사각형과 직사각형의 관계를 Public 상속을 써서 표현하면 틀립니다.
Public 상속의 의미는 기본 클래스 객체가 가진 모든것들이 파생 클래스 객체에도 그대로 적용된다고 단정 짓는다.
'언어 > Effective C++' 카테고리의 다른 글
[Effective C++] #2_#define, 매크로 사용의 대안 (0) | 2022.01.03 |
---|---|
[Effective C++] #33_오버라이딩 문제 (0) | 2022.01.03 |
[Effective C++] #31_파일 사이의 컴파일 의존성 (0) | 2021.12.31 |
[Effective C++] #30_인라인 함수 (0) | 2021.12.30 |
[Effective C++] #29_예외 안전성 확보 (0) | 2021.12.28 |