25
Effective C++ Chapter6. 상상 , 상상상 상상 상상 상상

Effective c++ Chapter6

  • Upload
    -

  • View
    92

  • Download
    0

Embed Size (px)

Citation preview

Effective C++Chapter6. 상속 , 그리고 객체 지향 설계

Item32. public 상속 모형은 반드시 is – a( 뭐는 뭐의 일종이다 )

• is - a 의 정의 :

어떤 클래스 D(derived) 를 클래스 B(Base) 로부터 상속을 통해 파생시킨 경우

D 타입의 모든 객체는 동시에 B 타입의 객체이지만 , 그 반대는 성립하지 않는다 .

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

모든 D 는 B 의 일종이다 (D is a B) 그 반대는 x

• C++ 과 자연어에서의 is – a 관계 차이

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

. . .};

새는 날 수 있다고 했지만 펭귄은 날지 못하는데…

Item32. public 상속 모형은 반드시 is – a( 뭐는 뭐의 일종이다 )

• 해결책 1: 새 종류의 구체화

• class Bird{. . . // fly 함수 선언 x};• class FlyingBird : public Bird{

virtual void fly(); // 날 수 있는 새의 fly 함수 선언 . . .};• class Penguin : public Bird{

. . . //Penguin 은 일반 Bird 클래스 상속으로 선언 x};

Item32. public 상속 모형은 반드시 is – a( 뭐는 뭐의 일종이다 )

• 해결책 2: 펭귄의 날기에 대한 에러처리

• Class Penguin : public Bird{public: virtual void fly() { error{“Attempt to make a penguin fly!”); } . . .};

혹은 Penguin 의 fly 구현 자체를 안 하는 방법도 있지만 유효하지 않은 코드는 컴파일 단계에서 막아주는게 좋음 (Item18)

이렇듯 자연어 is-a 관계와 헷갈리면 안된다 .

Item32. public 상속 모형은 반드시 is – a( 뭐는 뭐의 일종이다 )

Item33. 상속된 이름을 숨기지 말자• 유효범위 (scope)

• int x; // 전역 변수• void someFunc()

{ double x; // 지역 변수 std::cin >> x; // 입력을 받아 , 지역 변수 x 에 새 값을 읽어 넣는다 .

}

C++ 의 이름 가리기 규칙에 의해 자신이 처리하고 있는 유효범위에 같은 이름인 x 가 있기 때문에 더 이상 탐색하지 않는다 .

Item33. 상속된 이름을 숨기지 말자

유효범위에서 컴파일러가 이름을 찾는 순서 :mf2 를 찾는 경우 지역을 찾아보고 없으므로 Derived 클래스 탐색 De-rived 를 감싸고 있는 Base 탐색 여기서 mf2 를 발견 만약 여기에도 없었으면 마지막으로 전역을 탐색

Item33. 상속된 이름을 숨기지 말자

Derived 의 mf1() 과 mf3() 가 Base 로 부터 상속받은 것을 가상이건 비가상이건 , 모두다 가려 버린다 . 또 , 이름이 같은 함수이면 매개변수 타입이 달라도 가린다 .

Item33. 상속된 이름을 숨기지 말자

이럴 때 using 을 사용하여 본래 Base 의 함수를 상속받을 수 있다 .

Item34. 인터페이스 상속과 구현 상속의 차이를 구별하자• 인터페이스 상속 : 함수의 선언 부를 상속

• 구현 상속 : 함수의 구현 부를 상속

• 여러 가지 상황에 따라 인터페이스 상속만 필요할 경우가 있고 구현 상속이 필요할 경우도 있다 .

Item34. 인터페이스 상속과 구현 상속의 차이를 구별하자

Draw() 함수가 바로 순수 가상 함수이고 , error() 는 가상 함수 , objectID() 는 비가상 함수 이다 .

• 순수 가상 함수

• 함수의 인터페이스 만을 물려주려는 것

• Shape::draw 처럼 모든 객체는 그리기가 가능해야 하지만 모든 객체의 그리는 알고리즘이 같을 리가 없기 때문(ex) 직사각형 != 타원

Item34. 인터페이스 상속과 구현 상속의 차이를 구별하자

• 가상 함수

• 파생 클래스로 하여금 함수의 인터페이스뿐만 아니라 그 함수의 기본 구현도 물려받게 하는 것

• Shape::error 처럼 기본 인터페이스를 제공 하면서 파생 객체에서 error 가 났을 때 Shape 의 기본 error 구현을 가져다 사용 할 수 있게 한다 . 만약 기본 클래스의 구현을 사용하고 싶지 않다면 파생 클래스 개별적으로 구현도 가능하다 .

Item34. 인터페이스 상속과 구현 상속의 차이를 구별하자

• 비가상 함수

• Shape::objectID(), 클래스 파생에 상관없이 변하지 않는 동작에 쓰임

• 인터페이스와 그 함수의 필수적인 구현을 상속

• 파생 클래스에서 재정의 불가

Item34. 인터페이스 상속과 구현 상속의 차이를 구별하자

• 비가상 함수 인터페이스 (non-virtual-interface: NVI)• Class GameCharacter{

public: int healthValue() const {

. . . // 사전 동작 int retVal = doHealthValue(); // privat 의 가상함수를 호출 . . . // 사후 동작 return retVal; }private: virtual int doHealthValue() const { . . . }

Item35. 가상 함수 대신을 생각해 두자

사용자가 직접 가상함수를 호출 하지 않게 함으로 써 사전 동작과 사후 동작 사이에서 가상 함수를 호출 할 수 있게 되었다 .

Item35. 가상 함수 대신을 생각해 두자• std::function 으로 구현한 전략 패턴 • std::function 을 이용하여 함수 포인터

처럼 사용할 수 있다 .

• HealthCalcFunc 을 설정하는 함수를 따로두어 게임 진행 중에도 체력 계산치를 바꾸어 줄 수 있다 .

Item35. 가상 함수 대신을 생각해 두자• 고전적인 전략 패턴

고전적인 전략 패턴으로 HealthCalcFunc 클래스 계통에 파생 클래스를 추가함으로써 기존의 체력치 계산 알고리즘을 조정 / 개조 할 가능성도 열어 두었다는 점은 플러스 이다 .

Item36. 상속 받은 비가상 함수를 파생 클래스에서 재정의 X

• B 로부터 파생된 클래스인 D 에서 mf() 함수를 재정의 하게 되면 기본 클래스의 mf() 함수를 가리게 된다 .

• 위 처럼 동작하는 이유는 비 가상 함수를 정적 바인딩이기 때문이다 . pB 는 B 에대한 포인터로 선언 되었기 때문에 비 가상함수 mf() 가 반드시 B 에 존재 할거라 생각 하는 것이다 .

• 또 파생클래스인 D 에서 mf() 를 호출 할 때 B 의 mf() 로 갈지 D 의 mf() 로 갈지 난해한 상황도 발생한다 .

Item37. 상속 받은 기본 매개변수 값은 절대 재정의 X

Item37. 상속 받은 기본 매개변수 값은 절대 재정의 X

pc 의 동적타입은 Circle*

pr 의 동적타입은 Rectangle*

가상 함수는 동적 바인딩 된다 .

pr 의 동적 타입은 Rectangle* 이므로 Rectangle 의 draw 함수를 불러 오지만 기본 매개변수는 정적으로 바인딩 되기 때문에 정적 타입인 Shape* 의 매개변수를 가져 오는 참사가 발생하게 된다 .

예상 할 수 없는 결과가 나올지 모르니 매개변수는 건들지 말자 .

• 그래도 매개변수를 건들고 싶다면…

비가상 인터페이스 관용구 (NVI) 를 사용하자 (Item 35)

가상 함수를 private 으로 두고 이를 호출하는 비가상 함수를 기본 클래스에 두는 방식

이를 이용하여 비가상 함수가 매개변수를 지정할 수 있게 할 수 있다 .

Item37. 상속 받은 기본 매개변수 값은 절대 재정의 X

• 객체 합성 : 어떤 타입의 객체가 다른 타입의 객체들을 포함하고 있는 관계

Item38. has a, is a 모형화할 때 객체합성을 이용하자

• 응용 영역 : 객체 중 일상생활에서 볼 수 있는 것을 본뜬 것(ex) 사람 , 이동수단

• 구현 영역 : 버퍼 , 뮤텍스 , 탐색트리등 시스템 구현만을 위한 인공물이 속한 객체

• 객체 합성이 응용 영역에서 일어나면 has-a 관계

구현 영역에서 일어나면 is-implemented-in-terms-of 관계이다 .

Item38. has a, is a 모형화할 때 객체합성을 이용하자

• has- a 관계

전에 보여주었던 Person 과 Address 의 관계

• is-implemented-in-terms-of 관계가 필요한 예

set 템플릿을 list 에서 파생된 형태로 만들고 싶을 때

is-a 관계로 했더니 list 의 중복 원소를 가질 수 있는 기본 성질을 set 에서는 적용할 수가 없다 .

Item38. has a, is a 모형화할 때 객체합성을 이용하자

Item38. has a, is a 모형화할 때 객체합성을 이용하자이러한 상황일 때 is-implemented-in-terms-of 관계를 이용하면 된다 .