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


Answers

Bjarne Stroustrup과인터뷰에서 :

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

Question

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







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

이것은 결코 문제가되지 않을 수도 있지만 언젠가는 당신이 수십억 시간의 인스턴스가되는 마이크로 데이터 구조를 가지고 있다면 그렇게 될 것입니다.




w : 다중 상속 참조.

다중 상속은 비판을 받았으며, 따라서 여러 언어로 구현되지 않았습니다. 비판에는 다음이 포함됩니다.

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

C ++ / Java 스타일 생성자를 사용하는 언어의 다중 상속은 생성자 및 생성자 체인의 상속 문제를 악화 시키므로 이러한 언어에서 유지 관리 및 확장 성 문제가 발생합니다. 커스터마이징 패러다임 (constructor chaining paradigm) 하에서는 매우 다양한 구성 메소드를 사용하여 상속 관계에있는 객체를 구현하기가 어렵습니다.

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

나는 이것 대신에 다른 일을 할 수 있습니까?

그래 넌 할수있어. 나는 GoF 에서 훔칠거야.

  • 구현이 아닌 인터페이스에 프로그램하십시오.
  • 상속에 대한 컴포지션 선호



구체적인 객체에 대한 MI의 핵심 문제는 합법적으로 "A가되고 B"가되어야하는 객체가 거의 없다는 것입니다. 따라서 논리적 근거에 대한 올바른 해결책은 거의 없습니다. 훨씬 더 자주, 당신은 C가 A 나 B의 역할을 할 수있는 객체 C를 가지고 있습니다. 이것은 인터페이스 상속과 합성을 통해 얻을 수 있습니다. 그러나 여러 개의 인터페이스를 상속하는 것은 여전히 ​​실수입니다. MI의 일부분입니다.

특히 C ++의 경우 기능의 주요 약점은 다중 상속의 실제 존재가 아니라 거의 항상 잘못된 형식의 허용되는 일부 구문입니다. 예를 들어, 다음과 같은 동일한 객체의 여러 사본을 상속 :

class B : public A, public A {};

DEFINITION에 의해 ​​조작됩니다. 영어로 번역 된 것은 "B는 A와 A"입니다. 따라서 인간 언어에서도 심각한 모호성이 있습니다. "B가 2 As"또는 "B is A"를 의미 했습니까? 그러한 병적 인 코드를 허용하고, 사용 예제를 만들기가 더 어려워서 후속 언어로 기능을 유지하는 경우를 만들 때 C ++은 아무런 도움이되지 못했습니다.




모든 프로그래밍 언어는 장단점이있는 객체 지향 프로그래밍의 처리 방법이 약간 다릅니다. C ++의 버전은 성능에 중점을두고 있으며 잘못된 코드를 작성하기가 쉽지 않은 부수적 인 단점이 있습니다. 이는 다중 상속에 해당합니다. 따라서 프로그래머가이 기능을 사용하지 못하도록하는 경향이 있습니다.

다른 사람들은 다중 상속이 어째서 좋지 않은가에 대한 문제를 다루었습니다. 그러나 우리는 그것이 안전하지 않기 때문에 그것을 피하는 이유가 더 많거나 적은 것을 암시하는 꽤 많은 의견을 보았습니다. 네, 그렇습니다.

C ++에서 흔히있는 것처럼, 기본 지침을 따르면 "어깨 너머로"보지 않아도 안전하게 사용할 수 있습니다. 핵심 아이디어는 "혼합"이라고 불리는 특별한 종류의 클래스 정의를 구별하는 것입니다. 클래스는 모든 멤버 함수가 가상 (또는 순수 가상) 인 경우 혼합입니다. 그런 다음 하나의 메인 클래스와 원하는만큼 많은 "믹스 인"을 상속받을 수 있지만 "가상"키워드로 믹스 인을 상속해야합니다. 예

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 { ..... };

제 제안은 클래스를 믹스 인 클래스로 사용하려는 경우 명명 규칙을 사용하여 코드를 읽는 사람이 무슨 일이 일어나고 있는지를 쉽게 확인하고 기본 가이드 라인의 규칙에 따라 놀고 있는지 확인하는 것입니다. . 또한 가상베이스 클래스의 작동 방식 때문에 믹스 인에 기본 생성자가있는 경우 훨씬 더 효율적으로 작동합니다. 모든 소멸자를 가상으로 만드는 것을 잊지 마십시오.

여기서 "믹스 인"이라는 단어를 사용하는 것은 매개 변수화 된 템플릿 클래스와 다릅니다 (좋은 설명을 보려면 이 링크 참조).하지만 용어의 정당한 사용이라고 생각합니다.

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




다중 상속을 피할 수는 없지만 '다이아몬드 문제'( http://en.wikipedia.org/wiki/Diamond_problem )와 같이 발생할 수있는 문제를 알아야하며 사용자에게 주어진 힘을주의 깊게 다루어야합니다 , 당신은 모든 힘으로해야한다.