C ++에서 다중 상속을 피해야하는 이유는 무엇입니까?


167

다중 상속을 사용하는 것이 좋은 개념입니까, 아니면 다른 작업을 대신 할 수 있습니까?

답변:


259

다중 상속 (MI로 약칭 됨)은 냄새가납니다 . 이는 일반적으로 나쁜 이유 때문에 수행되었으며 관리자의 얼굴로 날아갈 것입니다.

요약

  1. 상속 대신 기능의 구성을 고려하십시오.
  2. 공포의 다이아몬드에주의하세요
  3. 객체 대신 여러 인터페이스의 상속을 고려하십시오
  4. 때때로 다중 상속이 옳은 경우가 있습니다. 그렇다면 사용하십시오.
  5. 코드 검토에서 다중 상속 아키텍처를 방어 할 수 있도록 준비

1. 아마도 구성?

상속의 경우에도 마찬가지이므로 다중 상속의 경우에는 더욱 그렇습니다.

객체가 실제로 다른 객체를 상속해야합니까? A CarEngine직장에서 또는에서 상속받을 필요가 없습니다 Wheel. A CarEngine4 개 Wheel입니다.

컴포지션 대신 이러한 문제를 해결하기 위해 다중 상속을 사용하는 경우 잘못된 작업이 있습니다.

2. 공포의 다이아몬드

일반적으로, 당신은 클래스가 A다음 BC에서 모두 상속을 A. 그리고 (왜 나에게 묻지 말고) 누군가 DB와 에서 상속해야한다고 결정 합니다 C.

8 8 년 만에 이런 종류의 문제가 두 번 발생했으며 다음과 같은 이유로 인해 재미 있습니다.

  1. 아키텍처가 잘못 되었기 때문에 (실제로 전혀 존재해서는 안 됨 ) 처음부터 실수가 얼마나 되었습니까 (두 경우 D모두 B와 에서 모두 상속 받지 않아야 함).CC
  2. C ++에서는 부모 클래스 A가 손자 클래스에 두 번 존재 했기 때문에 유지 보수 담당자가 지불 한 금액이므로 D하나의 부모 필드 A::field를 업데이트하면 두 번 업데이트하고 (통과 B::fieldC::field) 무언가 잘못되고 충돌이 발생했습니다. (에서 포인터를 새로 작성 B::field하고 삭제 C::field...)

상속을 제한하기 위해 C ++에서 virtual 키워드를 사용하면 이것이 원하는 것이 아니라면 위에서 설명한 이중 레이아웃을 피할 수 있지만 어쨌든 내 경험상 아마도 뭔가 잘못했을 것입니다 ...

객체 계층에서는 계층이 그래프가 아닌 트리 (노드에 하나의 부모가 있음)로 유지해야합니다.

다이아몬드에 대한 자세한 내용 (edit 2017-05-03)

C ++의 Dread Diamond의 실제 문제는 ( 디자인이 사운드라고 가정하고 코드를 검토해야한다고 가정 ) 선택해야한다는 것입니다 .

  • 클래스 A가 레이아웃에 두 번 존재 하는 것이 바람직 합니까? 그것은 무엇을 의미합니까? 그렇다면 반드시 두 번 상속하십시오.
  • 한 번만 존재해야한다면 사실상 상속해야합니다.

이 선택은 문제에 내재되어 있으며 C ++에서는 다른 언어와 달리 언어 수준에서 디자인을 강요하지 않고 실제로 할 수 있습니다.

그러나 모든 힘과 마찬가지로 그 힘도 책임이 있습니다. 설계를 검토하십시오.

3. 인터페이스

위에서 언급 한 Dread of Diamond를 만나지 않기 때문에 0 개 또는 1 개의 구체적인 클래스와 0 개 이상의 인터페이스를 여러 번 상속하는 것이 좋습니다. 사실, 이것은 자바에서 일이 이루어지는 방식입니다.

C의에서 상속 할 때 일반적으로, 당신은 무엇을 의미 A하고 B사용자가 사용할 수 있다는 것입니다 C그것이 인 것처럼 A, 및 / 또는 것처럼이 있었다 B.

C ++에서 인터페이스는 다음과 같은 추상 클래스입니다.

  1. 모든 메소드가 순수 가상으로 선언 됨 ( = 0으로 접미어) (2017-05-03 제거)
  2. 멤버 변수 없음

하나의 실제 객체에 대한 다중 상속과 0 개 이상의 인터페이스는 "적은"것으로 간주되지 않습니다 (적어도 많지 않음).

C ++ 추상 인터페이스에 대한 추가 정보 (편집 2017-05-03)

첫째, 실제 기준은 상태가 없어야합니다 (즉,을 제외한 멤버 변수가 없음 this). 귀하의 추상 인터페이스의 요점은 계약을 게시하는 것입니다 ( "당신은 이런 식으로 저에게 전화 할 수 있습니다"). 추상적 가상 방법 만 갖는 한계는 의무가 아니라 디자인 선택이어야합니다.

둘째, C ++에서는 추가 비용 / 간접에도 불구하고 추상 인터페이스에서 사실상 상속하는 것이 합리적입니다. 그렇지 않으면 인터페이스 상속이 계층 구조에서 여러 번 나타나는 경우 모호성이 있습니다.

셋째, 객체 지향은 매우 중요하지만, 그렇지 않은 유일한 진실 아웃이 TM 에서 C ++. 올바른 도구를 사용하고 C ++에서 다른 종류의 솔루션을 제공하는 다른 패러다임을 항상 기억하십시오.

4. 다중 상속이 정말로 필요합니까?

어쩔 땐 그래.

일반적으로, 당신의 C클래스에서 상속되지 ABAB(즉,하지 동일한 계층 구조에서 일반적으로, 다른 개념 등의 아무것도)이 관련이없는 개체가 있습니다.

예를 들어, NodesX, Y, Z 좌표 시스템을 사용하여 많은 기하학적 계산 (아마도 점, 기하학적 객체의 일부)을 수행 할 수 있으며 각 노드는 다른 에이전트와 통신 할 수있는 자동 에이전트입니다.

아마 당신은 이미 두 라이브러리 자체 네임 스페이스 각각에 액세스 할 수 있습니다 (네임 스페이스를 사용하는 또 다른 이유를 ...하지만 당신은, 당신을 네임 스페이스를하지 사용할 수 있습니까?) 한 존재 geo와 다른 존재를ai

자신이 그래서 own::Node에서 모두 파생를 ai::Agent하고 geo::Point.

이 때 컴포지션을 대신 사용하지 말아야하는지 스스로에게 물어봐야 할 순간입니다. 경우 own::Node정말 정말 둘 다 ai::Agent하고 geo::Point, 다음 구성은하지 않습니다.

그런 다음 own::Node3D 공간에서의 위치에 따라 다른 상담원과 의사 소통 할 수있는 다중 상속이 필요 합니다.

(당신은 점에 유의거야 ai::Agentgeo::Point완전히, 완전히, 완전히 관련이없는 ...이 크게 다중 상속의 위험을 감소)

다른 경우 (편집 2017-05-03)

다른 경우가 있습니다 :

  • 구현 세부 사항으로 (희망적으로 개인) 상속 사용
  • 정책과 같은 일부 C ++ 관용구는 다중 상속을 사용할 수 있습니다 (각 부분이를 통해 다른 부분과 통신해야하는 경우 this)
  • std :: exception의 가상 상속 (예외에는 가상 상속이 필요합니까? )
  • 기타

때로는 컴포지션을 사용할 수 있으며 때로는 MI가 더 좋습니다. 요점은 다음과 같습니다. 선택의 여지가 있습니다. 책임감있게 코드를 검토하십시오.

5. 다중 상속을해야합니까?

대부분의 경우 내 경험으로는 그렇지 않습니다. MI는이 더미에 게으른에 의해 사용될 수 있기 때문에 (A 만들기 같은 결과를 실현하지 않고 함께 기능, 작동하는 것 같다 경우에도 올바른 도구가 아닙니다 Car둘 모두 Engine와를 Wheel).

그러나 때때로 그렇습니다. 그리고 그 당시에는 MI보다 나은 것이 없습니다.

그러나 MI는 냄새가 나기 때문에 코드 검토에서 아키텍처를 방어 할 수 있도록 준비하십시오. 방어 할 수없는 경우 방어하지 않는 것이 좋습니다.


4
나는 그것이 완벽하게 맞더라도 위임에 대한 저축이 그것을 사용하지 않는 프로그래머들에게 혼란을 보상하지 않지만 그렇지 않으면 좋은 요약이 될 필요가 없으며 그렇게 유용하지 않다고 주장한다.
Bill K

2
MI를 사용하는 코드에는 그 이유를 설명하는 코드 바로 옆에 주석이 있어야하므로 코드 검토에서 구두로 설명 할 필요가 없습니다. 그렇지 않으면 귀하의 검토자가 아닌 사람이 귀하의 코드를 볼 때 귀하의 올바른 판단에 의문을 제기 할 수 있으며 귀하는이를 방어 할 기회가 없습니다.
Tim Abell

" 위에서 설명한 공포의 다이아몬드를 만나지 않기 때문입니다. "왜 그렇지 않습니까?
curiousguy

1
옵저버 패턴에 MI를 사용합니다.
Calmarius

13
@ BillK : 물론 필요하지 않습니다. MI가없는 터닝 완료 언어가있는 경우 MI를 사용하여 언어로 수행 할 수있는 모든 작업을 수행 할 수 있습니다. 따라서 필요하지 않습니다. 이제까지. 그것은 매우 유용한 도구가 될 수 있고 소위 드레드 다이아몬드라고 할 수 있습니다. 실제로 추론하기는 상당히 쉽고 일반적으로 문제가되지 않습니다.
Thomas Eding

145

Bjarne Stroustrup과인터뷰에서 :

사람들은 다중 상속이 필요하지 않다고 말합니다. 다중 상속으로 할 수있는 것은 단일 상속으로도 할 수 있기 때문입니다. 내가 언급 한 위임 트릭을 사용하면됩니다. 또한 단일 상속으로 수행하는 작업은 클래스를 통해 전달하여 상속하지 않고도 수행 할 수 있으므로 상속이 전혀 필요하지 않습니다. 실제로 포인터와 데이터 구조로 모두 할 수 있기 때문에 클래스가 필요하지 않습니다. 그러나 왜 그렇게 하시겠습니까? 언어 시설을 사용하는 것이 언제 편리합니까? 언제 해결 방법을 선호하십니까? 다중 상속이 유용한 경우를 보았고 복잡한 다중 상속이 유용한 경우도 보았습니다. 일반적으로, 나는 해결책으로 언어가 제공하는 기능을 사용하는 것을 선호합니다


6
C # 및 Java에서 놓친 C ++의 일부 기능이 있지만 디자인이 더 어려워지고 복잡해집니다. 예를 들어, 불변성 보장 const- 클래스가 실제로 가변 및 불변 변수를 가질 필요 가있을 때 (보통 인터페이스와 컴포지션을 사용하여) 어리석은 해결 방법을 작성 해야 했습니다. 그러나 다중 상속을 한 번도 놓치지 않았 으며이 기능이 없기 때문에 해결 방법을 작성해야한다고 생각한 적이 없습니다. 그 차이입니다. 모든 경우에 나는 이제까지 본 적이 없는 MI 더 나은 디자인 선택이 아닌 해결 방법입니다 사용.
BlueRaja-대니 Pflughoeft

24
+1 : 완벽한 답변 : 사용하지 않으려면 사용하지 마십시오.
Thomas Eding

38

피할 이유가 없으며 상황에서 매우 유용 할 수 있습니다. 그래도 잠재적 인 문제를 알고 있어야합니다.

가장 큰 것은 죽음의 다이아몬드입니다.

class GrandParent;
class Parent1 : public GrandParent;
class Parent2 : public GrandParent;
class Child : public Parent1, public Parent2;

이제 Child 내에 GrandParent의 "복사본"이 두 개 있습니다.

C ++은 이것을 생각했지만 가상 상속을 통해 문제를 해결할 수 있습니다.

class GrandParent;
class Parent1 : public virtual GrandParent;
class Parent2 : public virtual GrandParent;
class Child : public Parent1, public Parent2;

항상 디자인을 검토하고 상속을 사용하여 데이터 재사용을 절약하지 않도록하십시오. 구성과 같은 것을 표현할 수 있다면 (그리고 일반적으로 할 수있다) 이것은 훨씬 더 나은 접근 방법입니다.


21
상속을 금지하고 대신 컴포지션 만 사용하는 경우 항상에 두 개가 GrandParent있습니다 Child. 사람들은 언어 규칙을 이해하지 못할 것이라고 생각하기 때문에 MI에 대한 두려움이 있습니다. 그러나 이러한 간단한 규칙을 얻을 수없는 사람도 사소한 프로그램을 작성할 수 없습니다.
curiousguy

1
C ++ 규칙은 매우 정교합니다. 따라서 개별 규칙이 단순하더라도 규칙이 많기 때문에 적어도 인간이 따라야 할 모든 것이 단순하지는 않습니다.
Zebrafish

11

w : 다중 상속을 참조하십시오 .

다중 상속은 비판을 받았으므로 많은 언어로 구현되지 않습니다. 비판에는 다음이 포함됩니다.

  • 복잡성 증가
  • 시맨틱 모호성은 종종 다이아몬드 문제 로 요약된다 .
  • 단일 클래스에서 명시 적으로 여러 번 상속 할 수 없음
  • 상속 순서 변경 클래스 의미.

C ++ / Java 스타일 생성자를 사용하는 언어의 다중 상속은 생성자와 상속 체인의 상속 문제를 악화시켜 이러한 언어에서 유지 관리 및 확장 성 문제를 만듭니다. 생성자 체인 패러다임에 따라 매우 다양한 생성 방법을 가진 상속 관계에있는 객체를 구현하기가 어렵습니다.

COM 및 Java 인터페이스와 같은 인터페이스 (순수 추상 클래스)를 사용하도록이를 해결하는 현대적인 방법입니다.

이 대신 다른 일을 할 수 있습니까?

그래 넌 할수있어. 나는 GoF 에서 훔칠 것 입니다.

  • 구현이 아닌 인터페이스로 프로그램
  • 상속보다 컴포지션 선호

8

공공 상속은 IS-A 관계이며 때로는 클래스가 여러 다른 클래스의 유형이 될 수 있으며 때로는 이것을 반영하는 것이 중요합니다.

"Mixins"도 때때로 유용합니다. 그것들은 일반적으로 작은 클래스이며 일반적으로 어떤 것도 상속받지 않으며 유용한 기능을 제공합니다.

상속 계층 구조가 상당히 얕고 (거의 항상 그렇듯이) 잘 관리되는 한, 당신은 끔찍한 다이아몬드 상속을 얻지 못할 것입니다. 다이아몬드는 다중 상속을 사용하는 모든 언어에서 문제가되지 않지만 C ++의 처리는 종종 어색하고 때로는 수수께끼입니다.

다중 상속이 매우 편리한 경우가 있지만 실제로는 거의 없습니다. 다중 상속이 실제로 필요하지 않은 경우 다른 디자인 방법을 선호하기 때문일 수 있습니다. 혼란스러운 언어 구성을 피하고 싶고, 무슨 일이 일어나고 있는지 이해하기 위해 매뉴얼을 잘 읽어야하는 상속 사례를 쉽게 구축 할 수 있습니다.


6

다중 상속을 "피하지"말아야하지만 '다이아몬드 문제'( http://en.wikipedia.org/wiki/Diamond_problem )와 같이 발생할 수있는 문제를 알고 주의해서 제공하는 힘을 처리해야합니다. 모든 힘을 다해야합니다.


1
+1 : 포인터를 피하면 안되는 것처럼; 당신은 그들의 파급 효과를 알고 있어야합니다. 사람들은 어떤 히피족이 위생에 좋지 않다고 말하면서 인터넷에서 배운 문구 ( "MI는 악하다", "최적화하지 않는다", "고토는 악하다")를 덜걱 거려야합니다. 최악의 부분은 결코 그런 것들을 사용하려고 시도하지 않고 마치 성경에서 말하는 것처럼 가져가는 것입니다.
Thomas Eding

1
나는 동의한다. "피하지"말고 문제를 처리하는 가장 좋은 방법을 알고 있어야합니다. 어쩌면 나는 구성 적 특성을 사용하고 싶지만 C ++에는 그 특성이 없습니다. 어쩌면 나는 '핸들'자동 위임을 사용하고 싶지만 C ++에는 그렇지 않습니다. 그래서 나는 MI의 일반 도구와 무딘 도구를 여러 가지 목적으로, 아마도 동시에 사용합니다.
JDługosz

3

약간 추상적이 될 위험이 있기 때문에 나는 범주 이론의 틀 안에서 상속에 대해 생각하는 것이 밝혀졌다.

상속 관계를 나타내는 모든 클래스와 화살표를 생각하면 다음과 같습니다.

A --> B

class B에서 파생 된 것을 의미합니다 class A. 주어진

A --> B, B --> C

우리는 C가 A에서 파생 된 B에서 파생 되었기 때문에 C는 A에서 파생되었다고합니다.

A --> C

또한, 우리 A는 사소하게 A파생 된 모든 클래스에 대해 A상속 모델이 범주의 정의를 충족 한다고 말합니다 . 좀 더 전통적인 언어로, 우리는 Class모든 클래스와 형태와 상속 관계를 가진 객체를 가진 범주를 가지고 있습니다.

약간의 설정이지만, 다이아몬드 오브 둠을 살펴 보겠습니다.

C --> D
^     ^
|     |
A --> B

그늘진 모양의 다이어그램이지만 그렇게 할 것입니다. 그래서 D모두에서 상속 A, B그리고 C. 또한 OP의 문제 해결에 가까워지면서의 D모든 수퍼 클래스에서도 상속됩니다 A. 다이어그램을 그릴 수 있습니다

C --> D --> R
^     ^
|     |
A --> B
^ 
|
Q

이제 문제는 죽음의 다이아몬드와 관련된 여기 때입니다 CB공유가있는 특성 / 메소드 이름과 일이 모호한 얻을; 그러나 공유 된 동작을 이동 A하면 모호성이 사라집니다.

범주 측면에서 말하면, 우리가 원하는 A, B그리고 C경우 것이어야 B하고 C상속 Q후가 A의 서브 클래스로 다시 작성할 수 있습니다 Q. 이것은 A무언가를 pushout 이라고합니다 .

풀백D 이라는 대칭 구조도 있습니다 . 이것은 본질적으로 and 에서 상속하는 가장 유용한 유용한 클래스 입니다. 당신이 다른 클래스가있는 경우 즉, 다중 상속 하고 , 다음 클래스 인 의 하위 클래스로 다시 쓸 수는 .BCRBCDRD

다이아몬드 팁이 풀백 및 푸시 아웃인지 확인하면 이름 충돌 또는 유지 관리 문제를 일반적으로 처리 할 수있는 좋은 방법이됩니다.

참고 Paercebal답변 은 우리가 가능한 모든 클래스의 전체 범주 클래스에서 작업한다는 점을 감안할 때 위의 모델에서 그의 훈계가 암시되기 때문에 이것에 영감을주었습니다.

다중 상속 관계가 강력하고 문제가없는 복잡한 방법을 보여주는 것으로 그의 주장을 일반화하고 싶었습니다.

TL; DR 프로그램의 상속 관계를 범주를 형성하는 것으로 생각하십시오. 그런 다음 상속되는 여러 클래스를 푸시 아웃하고 대칭 적으로 만들어 풀백 인 공통 부모 클래스를 만들어 Diamond of Doom 문제를 피할 수 있습니다.


3

우리는 에펠을 사용합니다. 우리는 우수한 MI를 가지고 있습니다. 걱정 마. 문제 없습니다. 쉽게 관리 할 수 ​​있습니다. MI를 사용하지 않는 경우가 있습니다. 그러나 사람들이 다음과 같은 이유로 사람들이 알고있는 것보다 유용합니다. 목록에 너무 많으면 확실합니다 (위의 답변 참조).

우리에게 에펠 탑을 사용하는 MI는 도구 상자의 다른 도구와 마찬가지로 다른 도구와 마찬가지로 자연 스럽습니다. 솔직히, 우리는 다른 사람이 에펠을 사용하고 있지 않다는 사실에 대해 크게 걱정하지 않습니다. 걱정 마. 우리는 우리가 가진 것에 만족하고 당신을 한 번 보도록 초대합니다.

보고있는 동안 : Void-safety와 Null 포인터 역 참조 근절에주의하십시오. 우리 모두 MI 주변에서 춤을 추는 동안 포인터가 사라집니다! :-)


2

모든 프로그래밍 언어에는 장단점이있는 객체 지향 프로그래밍 처리 방식이 약간 다릅니다. C ++ 버전은 성능에 중점을두고 무효 코드를 작성하는 것이 혼란스럽게 쉽다는 단점이 있습니다. 이는 다중 상속에 해당됩니다. 결과적으로 프로그래머를이 기능에서 멀어지게하는 경향이 있습니다.

다른 사람들은 다중 상속이 좋지 않은 것에 대한 문제를 해결했습니다. 그러나 우리는 그것을 피해야하는 이유가 안전하지 않기 때문이라는 것을 암시하는 많은 의견을 보았습니다. 예, 아니오

C ++에서 종종 그렇듯이 기본 지침을 따르면 "어깨를 쳐다 보지 않아도"안전하게 사용할 수 있습니다. 핵심 아이디어는 "mix-in"이라는 특별한 종류의 클래스 정의를 구별하는 것입니다. 모든 멤버 함수가 가상 (또는 순수 가상) 인 경우 클래스는 믹스 인입니다. 그런 다음 단일 메인 클래스와 원하는만큼의 "mix-in"을 상속받을 수 있지만 "virtual"이라는 키워드로 mixin을 상속해야합니다. 예 :

class CounterMixin {
    int count;
public:
    CounterMixin() : count( 0 ) {}
    virtual ~CounterMixin() {}
    virtual void increment() { count += 1; }
    virtual int getCount() { return count; }
};

class Foo : public Bar, virtual public CounterMixin { ..... };

내 제안은 클래스를 믹스 인 클래스로 사용하려는 경우 코드를 읽는 사람이 무슨 일이 일어나고 있는지 확인하고 기본 지침의 규칙에 따라 연주하고 있는지 확인하기 위해 명명 규칙을 채택한다는 것입니다 . 그리고 가상 기본 클래스가 작동하는 방식 때문에 믹스 인에 기본 생성자가있는 경우 훨씬 더 효과적입니다. 또한 모든 소멸자를 가상으로 만들어야합니다.

여기서 "mix-in"이라는 단어를 사용하는 것은 매개 변수가있는 템플릿 클래스와 같지 않지만 ( 설명을 잘 보려면 이 링크 를 참조하십시오) 용어를 공정하게 사용한다고 생각합니다.

이제 이것이 다중 상속을 안전하게 사용하는 유일한 방법이라는 인상을 남기고 싶지 않습니다. 확인하기 쉬운 방법 중 하나입니다.


2

신중하게 사용해야합니다. 다이아몬드 문제 와 같은 상황이 복잡해질 수 있습니다.

대체 텍스트
(출처 : learncpp.com )


12
복사기는 스캐너와 프린터로 구성되어 있지 않고 스캐너와 프린터로 구성되어야하기 때문에 나쁜 예입니다.
Svante

2
어쨌든, a Printer조차도해서는 안됩니다 PoweredDevice. A Printer는 전원 관리가 아니라 인쇄용입니다. 특정 프린터를 구현하려면 일부 전원 관리가 필요할 수 있지만 이러한 전원 관리 명령은 프린터 사용자에게 직접 노출되어서는 안됩니다. 이 계층 구조의 실제 사용을 상상할 수 없습니다.
curiousguy


1

다이아몬드 패턴 외에도 다중 상속은 객체 모델을 이해하기 어렵게 만들고 유지 보수 비용을 증가시킵니다.

작곡은 본질적으로 이해하고 이해하고 설명하기가 쉽습니다. 코드를 작성하는 것은 지루할 수 있지만 좋은 IDE (Visual Studio로 작업한지 몇 년이 지났지 만 Java IDE에는 모두 훌륭한 구성 단축키 자동화 도구가 있습니다)는 그 장애물을 극복해야합니다.

또한 유지 관리 측면에서 비 마이너스 상속 인스턴스에서도 "다이아몬드 문제"가 발생합니다. 예를 들어 A와 B가 있고 클래스 C가 두 가지를 모두 확장하고 A에 오렌지 주스를 만드는 'makeJuice'방법이 있고 라임을 꼬아 서 오렌지 주스를 만들기 위해이를 확장하면 디자이너가 ' B '는 전류를 생성하고 생성하는'makeJuice '방법을 추가합니까? 'A'와 'B'는 현재 호환 가능한 "부모" 일 수 있지만 이것이 항상 그렇게된다는 것을 의미하지는 않습니다!

전반적으로 상속, 특히 다중 상속을 피하려는 경향이 최대입니다. 최대 값으로 예외가 있지만 코딩하는 예외를 가리키는 녹색 네온 사인이 깜박이는지 확인해야합니다. 그런 상속 트리를 볼 때마다 자신의 녹색 네온 네온에서 그릴 수 있도록 뇌를 훈련 시키십시오. sign), 그리고 당신은 모든 것이 때때로 의미가 있는지 확인합니다.


what happens when the designer for 'B' adds a 'makeJuice' method which generates and electrical current?어, 물론 컴파일 오류가 발생합니다 (사용이 모호한 경우).
Thomas Eding

1

콘크리트 물체의 MI와 관련된 주요 문제는 합법적으로 "A가되고 B가되어야"하는 물체가 거의 없기 때문에 논리적으로 올바른 해결책은 아닙니다. 훨씬 더 자주, 당신은 "C는 A 또는 B의 역할을 할 수 있습니다"라는 객체 C를 가지고 있는데, 이것은 인터페이스 상속과 구성을 통해 달성 할 수 있습니다. 그러나 여러 인터페이스의 실수 상속은 여전히 ​​MI이며 그중 일부일뿐입니다.

특히 C ++의 경우 기능의 주요 약점은 다중 상속의 실제 존재가 아니지만 거의 항상 변형되는 일부 구조입니다. 예를 들어 다음과 같은 동일한 객체의 여러 복사본을 상속합니다.

class B : public A, public A {};

DEFINITION의 형식이 잘못되었습니다. 영어로 번역하면 "B는 A와 A"입니다. 따라서 인간의 언어로도 모호한 점이 있습니다. "B에 2가 있습니다"또는 "B가 A입니다"라는 의미입니까? 그러한 병리학 적 코드를 허용하고 사용 사례를 악화시키는 것은 C ++이 기능을 후속 언어로 유지하는 경우에 유리하지 않았습니다.


0

상속보다 구성을 우선적으로 사용할 수 있습니다.

일반적인 느낌은 구성이 더 우수하다는 것입니다.


4
-1 : The general feeling is that composition is better, and it's very well discussed.구성이 더 좋다는 의미는 아닙니다.
Thomas Eding

실제로는 더 좋습니다.
Ali Afshar

12
더 좋지 않은 경우를 제외하고.
Thomas Eding

0

관련된 클래스 당 4/8 바이트가 필요합니다. (클래스 당이 포인터 하나).

이것은 결코 걱정할 수 없지만 언젠가는 수십억 시간에 이르는 마이크로 데이터 구조가 있다면 그렇게 될 것입니다.


1
그거 확실해? 일반적으로 심각한 상속을 받으려면 각 클래스 멤버마다 포인터가 필요하지만 상속 된 클래스로 확장해야합니까? 요컨대, 수십억 개의 조그마한 데이터 구조를 가진 횟수는 몇 번입니까?
David Thornley

3
@DavidThornley " MI에 대한 논쟁을 할 때 수십억 개의 작은 데이터 구조를 가지고 있습니까? "
curiousguy
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.