[ Effective C++ ] 항목 32 : public 상속 모형은 반드시 "is-a(...는...의 일종이다)"를 따르도록 만들자

Minsu._.Lighting·2023년 12월 7일
0

[ Effective C++ ] 정리 모음집
" C++ 프로그래머의 필독서, 스콧 마이어스의 Effective C++ 를 읽고 내용 요약 / 정리 "

[핵심]

" 클래스 사이에 맺을 수 있는 관계들을 명확하게 구분할 수 있도록 하고, 이 각각을 C++로 가장 잘 표현 하는 방법도 공부해 두자! "

  • public 상속의 의미는 "is-a(...는...의 일종)"이기 때문에 기본 클래스에 적용되는 모든 것들이 파생 클래스에 그대로 적용되어야 한다.

💡 C++의 public 상속

class Person { ... };
class Student : public Person { ... };
  • 모든 학생은 사람의 일종이지만(student is a Person), 모든 사람은 학생이 아니다
    - '사람'은 '학생'보다 일반적인 개념, '학생'은 '사람'을 더 특수하게 만든 한 종류

📌 상속 예시 1 - 기본적인 is-a 관계

void eat(const Person& p);			// 먹는 것은 누구든 한다
void study(const Student& a);		// 학과 공부는 학생만 한다

Person p;
Student s;

eat(p);								// p는 Person이니 문제 없다
eat(s);								// s는 Student이나 Person의 일종이니 문제 없다

study(s);							// s는 Student이므로 문제 없다
study(p);							// p는 Student가 아니다, 에러!

📌 상속 예시 2 - is-a 관계 판단 잘못

class Bird
{
public:
	virtual void fly();			// 새는 날 수 있다
    ...
};

class Penguin : public Bird		// 펭귄은 새이다
{
	...
};
  • 모든 새가 날 수 있는건 아니지만, 새는 날 수 있다.

📌 상속 예시 3 - 예시 2번을 좀더 명확하게!

class Bird
{
    ...							// fly 함수는 선언하지 않는다
};

class FlyingBird : public Bird
{
public:
	virtual void fly();			// fly 함수 선언
    ...							
};

class Penguin : public Bird
{
	...							// fly 함수는 선언하지 않는다
};
  • 날 수 있는 새, 그렇지 못한 새로 계통을 나누고 fly 함수를 맞게 넣어준다

📢 제작하는 프로그램에 따라 계통 분류가 나뉘기도 한다!
- 새의 '날기' 기능이 필요가 없다면 날 수 있는새, 그렇지 못한 새로 나눌 이유가 없다

📌 상속 예시 4 - 함수는 가상함수로, 계통에 따라 동작을 다르게!

void error(string& msg);

class Penguin : public Bird
{
public:
	virtual void fly() { error("펭귄은 못날아!"); }
    ...
};
  • 런타임 에러가 발생하지만 의도와는 동떨어진 방법...
    - "펭귄은 날 수 없다" 가 아닌 "펭귄이 날면 error가 발생한다" 이기 때문

  • 런타임시 오류를 찾아내는 것 보단 컴파일 단계에서 찾는게 더 좋은 설계!

class Bird
{
	...							// fly 함수가 선언되지 않았습니다.
};

class Penguin : public Bird
{
	...							// fly 함수가 선언되지 않았습니다.
};

Penguin p;

p.fly();						// 에러!


💡 C++의 public 상속

class Rectangle
{
public:
	virtual void setHeight(int newHeight);
    virtual void setHeight(int newHeight);
    
    virtual int height() const;
    virtual int width() const;
    ...
};

void make Bigger(Rectangle& r)
{
	int oldHeight = r.height();
    
    r.setWidth(r.width() + 10);
    
    assert(r.height() == oldHeight);
}

class Square : public Rectangle { ... };

Square s;
...
assert(s.width() == s.height());

makeBigger(s);

assert(s.width() == s.height());
  • 우리의 생각으로는 당연히 정사각형은 직사각형에 포함된다
    - 직사각형 : 가로, 세로 각 두변의 길이가 같은 사각형
    - 정사각형 : 네 변의 길이가 모두 같은 사각형
    - 정사각형은 직사각형이다. (Square is a Rectangle)

  • 하지만..
    - makeBigger() 함수는 가로길이만 10 늘린다...
    - 가로 길이만 바뀌기에 정사각형의 조건에 부합할 수 없다...
    - assert(s.width() == s.height()); 단정문도 부합하지 않게 된다...

📢 public 상속은 기본 클래스 객체가 가진 모든 것들이 파생 클래스 객체에도 그대로 적용된다고 단정하는 상속!
- 그렇기에 정사각형은 직사각형에게 상속을 받을 수 없다!

profile
오코완~😤😤

0개의 댓글

관련 채용 정보