6. Inheritance and Object-Oriented Design

C++에서의 객체지향 프로그래밍은 다른 언어에서의 그것과 조금 다르다. 그것을 알아보도록 하자.

32. Make sure public inheritance models “is-a”.

public 상속은 is-a이다. 명심하자.

  • public 상속은 “is-a”를 의미한다. 기반 클래스에 적용되는 모든 것들은 파생 클래스에도 적용되어야 한다. 모든 파생 클래스 오브젝트는 기반 클래스 오브젝트이기 때문이다.

33. Avoid hiding inherited names.

파생 클래스의 메소드로 기반 클래스의 메소드 이름을 숨기지 말라.

  • 파생 클래스 내의 이름은 기반 클래스 내의 이름을 숨긴다. public 상속에서는 이것은 절대 바람직하지 않다.
  • 숨겨진 이름을 다시 스코프 내에 인식되게 하려면, using 선언을 하거나 함수 포워딩을 하라.

34. Differentiate between inheritance of interface and inheritance of implementation.

public 상속에서 멤버 함수 인터페이스는 항상 상속된다. 순수 가상 함수의 목적은 파생 클래스가 인터페이스만 상속하게 하는 것이다. 일반 가상 함수의 목적은 파생 클래스가 인터페이스 및 기본 구현까지 상속하게 하는 것이다. 이것은 확장성 측면에서는 위험하다. 기본 구현은 다른 이름을 가진 protected 비 가상 함수로 정의해 놓는 것이 좋다. 모든 함수를 비가상으로 정의하거나 모든 함수를 가상으로 정의하는 것은 모두 위험하다.

  • 인터페이스의 상속은 구현의 상속과 다르다. public 상속에서는 파생 클래스는 항상 기반 클래스의 인터페이스를 상속한다.
  • 순수 가상 함수는 인터페이스의 상속만을 특정한다.
  • 일반 가상 함수는 인터페이스의 상속과 기본 구현의 상속을 특정한다.
  • 비가상 함수는 인터페이스의 상속과 필수 구현의 상속을 특정한다.

35. Consider alternatives to virtual functions.

가상 함수에 대해선 다음 대안들이 있다. private 가상 함수에 실제 구현을 넣고 public 비가상 래퍼 함수를 통해 이를 호출하는 것 (Template 패턴), std::function 등을 이용해 멤버 함수가 아니라 클래스에 독립적인 함수로 구현하는 것 (Strategy 패턴), 다른 클래스 계층 내의 가상 함수로 구현하는 것 등이 있다.

  • 가상 함수에 대한 대안은 NVI 이디엄과 전략 패턴의 여러 변종이 있다. NVI 이디엄은 템플릿 패턴의 예이다.
  • 멤버 함수에서 클래스 밖의 함수로 기능을 빼는 것은 클래스 내의 non-public 요소에 대한 접근을 하지 못하게 한다.
  • std::function 오브젝트는 일반화된 함수 포인터이다. 이런 오브젝트는 주어진 대상 시그니쳐와 호환 가능한 모든 호출 가능한 오브젝트를 지원한다.

36. Never redefine an inherited non-virtual function.

파생 클래스에서 상속된 비가상 함수를 재정의하지 말라. 디자인 오류일 뿐더러 생각대로 동작하지 않는다.

  • 파생 클래스에서 상속된 비가상 함수를 재정의하지 말라.

37. Never redefine a function’s inherited default parameter value.

가상 함수의 인자 기본값을 재정의하지 말라. 가상 함수는 동적 바인딩이고 인자 기본값은 정적 바인딩이기 때문에 생각대로 동작하지 않는다.

  • 가상 함수의 인자 기본값을 재정의하지 말라. 가상 함수는 동적 바인딩이고 인자 기본값은 정적 바인딩이다.

38. Model “has-a” or “is-implemented-in-terms-of” through composition.

컴포지션은 어떤 타입의 오브젝트가 다른 타입의 오브젝트를 포함하는 관계이다.

  • 컴포지션은 public 상속과는 완전히 다르다.
  • 애플리케이션 영역에서 컴포지션은 has-a이다. 구현 영역에서 컴포지션은 is-implemented-in-terms-of이다.

39. Use private inheritance judiciously.

private 상속은 인터페이스가 아닌 구현만 상속하겠다는 뜻이다. is-implemented-in-terms-of를 뜻한다. 이것은 public 상속과 컴포지션으로도 할 수 있다. 사실 그게 더 낫다. private 상속이 나은 때는 데이터가 없고 특정 기능을 구현하는 함수들이 있는 클래스만 상속할 때이다. 빈 기반 클래스 최적화를 수행하기 때문이다.

  • private 상속은 is-implemented-in-terms-of를 뜻한다. 이는 대개 컴포지션보다 못하지만, 파생 클래스가 protected 기반 멤버에 접근하거나 상속된 가상 함수를 재정의해야 할 때 유용하다.
  • 컴포지션과 달리 private 상속은 빈 기반 클래스 최적화를 수행한다. 이는 오브젝트 크기를 최소화하고자 하는 라이브러리 제작자들에게 유용하다.

40. Use multiple inheritance judiciously.

다중 상속을 할 때는 다이아몬드 문제를 막기 위해 중간 클래스들이 기반 클래스를 가상 상속하도록 하라. 다중 상속과 가상 상속은 꼭 필요할 때만 쓰라. 쓸 때는 기반 클래스를 가상 상속하는 중간 클래스들이 데이터를 담지 않도록 하라.

  • 다중 상속은 단일 상속보다 더 복잡하다. 모호성 문제가 있고 가상 상속을 필요로 한다.
  • 가상 상속은 크기, 속도, 초기화와 대입의 복잡성 문제가 있다. 가상 기반 클래스는 데이터가 없을 때 유용하다.
  • 다중 상속은 적합한 사용처가 있다. 구현을 돕는 클래스를 private 상속하면서 동시에 인터페이스 클래스를 public 상속하는 것 등이 있다.

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Google photo

Google의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

%s에 연결하는 중