C ++는 공통 공통 조상으로 다중 상속을 어떻게 처리합니까?


13

나는 C ++ 사람이 아니지만 이것에 대해 생각해야합니다. C ++에서는 다중 상속이 가능한데 왜 C #에서는 불가능합니까? (나는 다이아몬드 문제를 알고 있지만 여기서 내가 묻는 것은 아닙니다.) C ++는 여러 기본 클래스에서 상속 된 동일한 메소드 서명의 모호성을 어떻게 해결합니까? 왜 같은 디자인이 C #에 포함되지 않습니까?


3
완전성을 위해 "다이아몬드 문제"는 무엇입니까?
jcolebrand

1
@jcolebrand en.wikipedia.org/wiki/Multiple_inheritance 참조 다이아몬드 문제
l46kok

1
물론, 나는 그것을 봤지만 그것이 Sandeep이 무엇을 의미하는지 어떻게 알 수 있습니까? "공유 공통 조상을 가진 다중 상속"이 더 직접적인 경우, 모호한 이름으로 무언가를 참조하려는 경우
jcolebrand

1
@ jcolebrand 나는 질문에서 얻은 것을 반영하도록 편집했습니다. 나는 그가 문맥에서 위키피디아에서 언급 한 다이아몬드 문제를 의미한다고 가정한다. 다음에 우호적 인 의견을 삭제하고 반짝이는 새로운 제안 편집 도구를 사용하십시오 :)
Earlz

1
@Earlz는 참조를 이해할 때만 작동합니다. 그렇지 않으면 나는 나쁜 편집을하고 있으며, 그것은 단지 나쁜 juju입니다.
jcolebrand

답변:


24

C ++에서는 다중 상속이 가능한데 왜 C #에서는 불가능합니까?

자바에서 그들은 언어를 쉽게 배우기 위해 언어의 표현성을 제한하고 싶었습니다. 여러 상속을 사용하는 코드는 종종 자신의 이익을 위해 너무 복잡하기 때문입니다. 그리고 전체 다중 상속은 구현하기가 훨씬 더 복잡하기 때문에 가상 머신도 많이 단순화했습니다 (여러 상속은 객체의 중간에 포인터를 유지해야하기 때문에 가비지 수집기와 특히 잘못 상호 작용합니다) )

그리고 C #을 디자인 할 때 Java를 보았을 때, 전체 다중 상속이 그리 많이 그리워하지 않고 일을 단순하게 유지하기로 선택했다는 것을 알았습니다.

C ++는 여러 기본 클래스에서 상속 된 동일한 메소드 서명의 모호성을 어떻게 해결합니까?

하지 않습니다 . 특정 기본 클래스에서 기본 클래스 메소드를 명시 적으로 호출하는 구문이 있지만 가상 메소드 중 하나만 대체 할 수있는 방법이 없으며 서브 클래스에서 메소드를 대체하지 않으면 기본을 지정하지 않고 호출 할 수 없습니다. 수업.

왜 같은 디자인이 C #에 포함되지 않습니까?

통합 할 것이 없습니다.


Giorgio는 주석에서 인터페이스 확장 메소드를 언급 했으므로 믹스 인이 무엇이며 다양한 언어로 구현되는 방법을 설명하겠습니다.

Java 및 C #의 인터페이스는 선언 방법으로 만 제한됩니다. 그러나 인터페이스를 상속하는 각 클래스에서 메소드를 구현해야합니다. 그러나 많은 클래스의 인터페이스가 있으며, 여기서 다른 메소드와 관련하여 일부 메소드의 기본 구현을 제공하는 것이 유용합니다. 일반적인 예는 유사합니다 (의사 언어).

mixin IComparable {
    public bool operator<(IComparable r) = 0;
    public bool operator>(IComparable r) { return r < this; }
    public bool operator<=(IComparable r) { return !(r < this); }
    public bool operator>=(IComparable r) { return !(r > this); }
    public bool operator==(IComparable r) { return !(r < this) && !(r > this); }
    public bool operator!=(IComparable r) { return r < this || r > this; }
};

풀 클래스와 다른 점은 데이터 멤버를 포함 할 수 없다는 것입니다. 이를 구현하기위한 몇 가지 옵션이 있습니다. 분명히 다중 상속은 하나입니다. 그러나 다중 상속은 구현하기가 다소 복잡합니다. 그러나 여기에는 실제로 필요하지 않습니다. 대신 많은 언어가 클래스와 메소드 구현 저장소에 의해 구현 된 인터페이스에서 믹스 인을 클래스 자체에 주입하거나 중간 기본 클래스가 생성되어 배치되어 인터페이스에 분할하여이를 구현합니다. 이것은 Ruby와 D 로 구현되고, Java 8로 구현되며, 반복 적으로 반복되는 템플릿 패턴을 사용하여 C ++에서 수동으로 구현할 수 있습니다 . 위의 CRTP 형식은 다음과 같습니다.

template <typename Derived>
class IComparable {
    const Derived &_d() const { return static_cast<const Derived &>(*this); }
public:
    bool operator>(const IComparable &r) const { r._d() < _d(); }
    bool operator<=(const IComparable &r) const { !(r._d() < _d(); }
    ...
};

다음과 같이 사용됩니다.

class Concrete : public IComparable<Concrete> { ... };

일반 기본 클래스처럼 가상으로 선언 할 것이 필요하지 않으므로 템플릿에서 인터페이스를 사용하는 경우 유용한 최적화 옵션을 열어 둡니다. C ++에서는 여전히 두 번째 부모로 상속되지만 다중 상속을 허용하지 않는 언어에서는 단일 상속 체인에 삽입되므로 더 비슷합니다.

template <typename Derived, typename Base>
class IComparable : public Base { ... };
class Concrete : public IComparable<Concrete, Base> { ... };

컴파일러 구현은 가상 디스패치를 ​​피하거나 피할 수 있습니다.

C #에서 다른 구현이 선택되었습니다. C #에서 구현은 완전히 분리 된 클래스의 정적 메소드이며 주어진 이름의 메소드가 존재하지 않지만 "확장 메소드"가 정의 된 경우 메소드 호출 구문은 컴파일러에 의해 적절하게 해석됩니다. 이것은 확장 메소드를 이미 컴파일 된 클래스에 추가 할 수 있다는 장점과 그러한 메소드를 재정의 할 수 없다는 단점이 있습니다 (예 : 최적화 된 버전 제공).


인터페이스 확장 메소드를 사용하여 다중 상속이 Java 8에 도입 될 것이라고 언급 할 수 있습니다.
Giorgio

@Giorgio : 아니요, 다중 상속은 Java로 도입되지 않을 것입니다. Mixin은 여러 가지 상속을 사용해야하는 많은 이유 와 CRTP (Curiously Recurring Template Pattern) 를 사용해야하는 대부분의 이유를 다루고 있으며 다중 상속이 아닌 CRTP와 거의 동일하게 작동합니다.
Jan Hudec

다중 상속에는 객체 중간에 대한 포인터 가 필요 하지 않다고 생각 합니다. 그렇다면 여러 인터페이스 상속에도 필요합니다.
svick

@ svick : 아니오, 그렇지 않습니다. 그러나 대안은 멤버 액세스를위한 가상 디스패치가 필요하므로 훨씬 덜 효율적입니다.
Jan Hudec

나의 것보다 훨씬 더 완전한 대답을 위해 +1.
Nathan C. Tresch

2

대답은 네임 스페이스 충돌의 경우 C ++에서 올바르게 작동하지 않는다는 것입니다. 참조 . 네임 스페이스 충돌을 피하려면 포인터로 모든 종류의 회전을 수행해야합니다. 나는 MS에서 Visual Studio 팀에서 일했으며 적어도 부분적으로 그들이 위임을 개발 한 이유는 네임 스페이스 충돌을 완전히 피하는 것이 었습니다. Preiouvsly 나는 인터페이스도 다중 상속 솔루션의 일부라고 생각했지만 실수했습니다. 인터페이스는 실제로 놀랍고 C ++, FWIW에서 작동하도록 만들 수 있습니다.

위임은 특히 네임 스페이스 충돌을 해결합니다. 5 개의 클래스에 위임 할 수 있으며 5 개의 클래스 모두 메서드를 첫 번째 클래스 멤버로 범위에 내 보냅니다. 외부에서 보면이 다중 상속입니다.


1
이것이 C #에 MI를 포함시키지 않는 주된 이유 일 가능성은 거의 없습니다. 또한이 글에서는 "네임 스페이스 충돌"이 없을 때 MI가 C ++에서 작동하는 이유에 대한 답변을 제공하지 않습니다.
Doc Brown

@DocBrown 저는 Visual Studio 팀의 MS에서 근무했으며 네임 스페이스 충돌을 피하기 위해 적어도 부분적으로 위임 및 인터페이스를 개발 한 이유를 확신합니다. 질문의 질에 관해서는, meh. downvote를 사용하면 다른 사람들은 유용하다고 생각하는 것 같습니다.
Nathan C. Tresch 2012 년

1
나는 그것이 정답이라고 생각하기 때문에 당신의 답을 내려 놓을 의도는 없습니다. 그러나 귀하의 답변에 따르면 MI는 C ++에서 완전히 사용할 수 없다고 가정합니다. 이것이 C #에서 MI를 도입하지 않은 이유입니다. C ++에서 MI를별로 좋아하지는 않지만 MI를 완전히 사용할 수는 없다고 생각합니다 .
Doc Brown

1
이유 중 하나이며 작동하지 않는다는 것을 의미하지는 않았습니다. 컴퓨팅에있어 결정적이지 않은 것이있을 때 나는 그것이 "부러졌다"고 말하거나 "부두와 같다면, 그것이 작동하거나 작동하지 않을 수있다. : D
Nathan C. Tresch

1
"네임 스페이스 충돌"이 결정적이지 않습니까?
Doc Brown
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.