나는 C ++ 사람이 아니지만 이것에 대해 생각해야합니다. C ++에서는 다중 상속이 가능한데 왜 C #에서는 불가능합니까? (나는 다이아몬드 문제를 알고 있지만 여기서 내가 묻는 것은 아닙니다.) C ++는 여러 기본 클래스에서 상속 된 동일한 메소드 서명의 모호성을 어떻게 해결합니까? 왜 같은 디자인이 C #에 포함되지 않습니까?
나는 C ++ 사람이 아니지만 이것에 대해 생각해야합니다. C ++에서는 다중 상속이 가능한데 왜 C #에서는 불가능합니까? (나는 다이아몬드 문제를 알고 있지만 여기서 내가 묻는 것은 아닙니다.) C ++는 여러 기본 클래스에서 상속 된 동일한 메소드 서명의 모호성을 어떻게 해결합니까? 왜 같은 디자인이 C #에 포함되지 않습니까?
답변:
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 #에서 구현은 완전히 분리 된 클래스의 정적 메소드이며 주어진 이름의 메소드가 존재하지 않지만 "확장 메소드"가 정의 된 경우 메소드 호출 구문은 컴파일러에 의해 적절하게 해석됩니다. 이것은 확장 메소드를 이미 컴파일 된 클래스에 추가 할 수 있다는 장점과 그러한 메소드를 재정의 할 수 없다는 단점이 있습니다 (예 : 최적화 된 버전 제공).
대답은 네임 스페이스 충돌의 경우 C ++에서 올바르게 작동하지 않는다는 것입니다. 참조 이 . 네임 스페이스 충돌을 피하려면 포인터로 모든 종류의 회전을 수행해야합니다. 나는 MS에서 Visual Studio 팀에서 일했으며 적어도 부분적으로 그들이 위임을 개발 한 이유는 네임 스페이스 충돌을 완전히 피하는 것이 었습니다. Preiouvsly 나는 인터페이스도 다중 상속 솔루션의 일부라고 생각했지만 실수했습니다. 인터페이스는 실제로 놀랍고 C ++, FWIW에서 작동하도록 만들 수 있습니다.
위임은 특히 네임 스페이스 충돌을 해결합니다. 5 개의 클래스에 위임 할 수 있으며 5 개의 클래스 모두 메서드를 첫 번째 클래스 멤버로 범위에 내 보냅니다. 외부에서 보면이 다중 상속입니다.