이펙티브 C++
https://www.yes24.com/Product/Goods/17525589
페이지 230p ~ 239p
이펙티브 C++(230p ~ 239p)
6. 상속, 그리고 객체 지향 설계
- C++의 OOP는 일반적인 OOP보다 조금 더 생각할 부분이 있다.
- 상속은 단일 상속과 다중 상속이 가능하다.
- 상속 관계 하나하나가 public, protected, private 성질을 가질 수 있다.
- 가상 상속과 비가상 상속이 있다.
- C++에서 OOP 개념은 다음과 같다.
- public 상속은 반드시
is-a
관계를 뜻해야 한다. - 가상 함수의 의미는 ‘인터페이스가 상속되어야 한다.’ 이지만 비가상 함수는 ‘인터페이스와 구현이 둘 다 상속되어야 한다.’이다.
- public 상속은 반드시
항목 32: public 상속 모형은 반드시 is-a
를 따르도록 만들자
- D(Derived)를 클래스 B(Base)로부터 public 상속을 통해 파생시켰다면, 이는 C++ 컴파일러에게 D 타입으로 만들어진 모든 객체는 또한 B 타입의 객체이지만, 그 반대는 되지 않는다.
- 다시 말해 B는 D보다 더 일반적인 개념을 나타내며, D는 B보다 더 특수한 개념을 나타낸다고 알리는 것이다.
- B 타입의 객체가 쓰일 수 있는 곳에는 D 타입의 객체도 마찬가지로 쓰일 수 있다고 단정하는 것이다.
class Person {};
class Student: public Person {};
- 위와 같은 상속 계통을 가진 클래스가 있을 때, Person 타입의 인자를 기대하는 함수는 Student 객체도 받아들일 수 있다.(포인터 혹은 참조자)
void eat(const Person& p);
void study(const Student& s);
Person p;
Student s;
eat(p);
eat(s);
study(s);
study(p); // 에러 p는 student가 아님
- 이는 public 상속에서만 통한다.
- public 상속 관계가
is-a
관계가 똑같은 뜻이라는 이야기지만 판단을 잘못할 수 있는 가능성도 있다.
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 Bird {
public:
virtual void fly() { error("Attempt to make a penguin fly!"); }
};
- 그러나 이 코드가 말하고자 하는 바는 뉘앙스가 조금 다르다.
- 이 코드는
펭귄은 날 수 없다
라고 말하는 것이 아니라펭귄은 날 수 있다. 그러나 실제로 펭귄이 날려고 하면 에러가 난다
라고 말하는 것이다. - 펭귄을 날 수 없게 하려면 컴파일러가
fly
를 호출하지 못하도록 해야 한다. - 유효하지 않은 코드를 컴파일 단계에서 막아 주는 인터페이스가 좋은 인터페이스이다.
- 따라서 펭귄의 무모한 비행을 컴파일 타임에 거부하는 것이 런타임에 알아채는 설계보다 좋다고 말할 수 있다.
- 이 코드는
메모
항목 32: public 상속 모형은 반드시 is-a
를 따르도록 만들자
- public 상속의 의미는
is-a
이다. 기본 클래스에 적용되는 모든 것들이 파생 클래스에 그대로 적용되어야 한다. 왜냐하면 모든 파생 클래스 객체는 기본 클래스 객체의 일종이기 때문이다.
'책 > 이펙티브 C++' 카테고리의 다른 글
이펙티브 C++(230p ~ 239p) (0) | 2024.01.30 |
---|---|
이펙티브 C++(240p ~ 250p) (0) | 2024.01.30 |
이펙티브 C++(210p ~ 220p) (2) | 2024.01.26 |
이펙티브 C++(201p ~ 210p) (0) | 2024.01.25 |
이펙티브 C++(191p ~ 200p) (0) | 2024.01.25 |