it-swarm.com.ru

Почему множественное наследование не разрешено в Java или C #?

Я знаю, что множественное наследование не разрешено в Java и C #. Многие книги просто говорят, множественное наследование не допускается. Но это можно реализовать с помощью интерфейсов. Ничего не обсуждается, почему это не разрешено. Кто-нибудь может сказать мне точно, почему это не разрешено?

100
Abdulsattar Mohammed

Краткий ответ: потому что разработчики языка решили не делать этого.

По сути, казалось, что и разработчики .NET, и Java не допускали множественное наследование, потому что они полагали, что добавление MI добавило слишком много сложности к языкам, в то же время предоставив слишком мало преимуществ.

Для более увлекательного и глубокого прочтения в Интернете доступны несколько статей с интервью с некоторыми языковыми дизайнерами. Например, для .NET Крис Брамм (который работал в MS над CLR) объяснил причины, по которым они решили не делать:

  1. Разные языки на самом деле имеют разные ожидания того, как MI работает. Например, как конфликты решены ли дублирующие базы объединены или избыточны. Прежде чем мы сможем реализовать MI в CLR, мы должны сделать опрос всех языков, рисунок из общих понятий, и решить как выразить их в не зависящая от языка манера. Мы также должны решить, принадлежит ли МИ в CLS и что это будет значить для языки, которые не хотят этого понятия (предположительно VB.NET, например). Из Конечно, это бизнес, в котором мы находимся как общеязыковая среда выполнения, но мы не удосужился сделать это для MI еще.

  2. Количество мест, где MI действительно подходит, на самом деле вполне маленький. Во многих случаях несколько Наследование интерфейса может получить работу сделано вместо В других случаях вы можете быть в состоянии использовать инкапсуляцию и делегация. Если бы мы должны были добавить немного другая конструкция, как mixins, это будет на самом деле больше мощный?

  3. Наследование нескольких реализаций вносит много сложности в реализация. Эта сложность ударное литье, макет, отправка, доступ к полям, сериализация, идентификация сравнения, проверяемость, рефлексия, дженерики и, вероятно, много других мест.

Вы можете прочитать полную статью здесь.

Для Java вы можете прочитать эту статью :

Причины опущения нескольких наследование от языка Java в основном проистекает из «простой, объектно-ориентированной и знакомой» цели. Как простой язык, создатели Java хотел язык, который большинство разработчиков мог понять без обширных повышение квалификации. С этой целью они работали до сделать язык похожим на C++ как можно (знакомо) без ношения над ненужной сложностью C++ (просто). 

По мнению дизайнеров, несколько наследование вызывает больше проблем и путаница, чем она решает. Таким образом, они режут множественное наследование от языка (так же, как они режут оператор перегрузка). Дизайнеры обширные Опыт С ++ научил их этому множественное наследование просто не стоило головная боль.

133
Razzie

Многократное наследование реализации это то, что не допускается. 

Проблема в том, что компилятор/среда выполнения не могут понять, что делать, если у вас есть класс Cowboy и Artist, оба с реализациями для метода draw (), а затем вы пытаетесь создать новый тип CowboyArtist. Что происходит, когда вы вызываете метод draw ()? Кто-то лежит на улице мертвым или у вас есть прекрасная акварель?

Я считаю, что это называется проблемой двойного бриллиантового наследования.

90
duffymo

Причина: Java очень популярна и легко кодируется из-за своей простоты.

Так что когда-либо разработчики Java чувствуют себя трудными для понимания программистами, они стараются избегать этого. Одним из таких видов собственности является множественное наследование.

  1. Они избегали указателей
  2. Они избежали множественного наследования.

Проблема множественного наследования: Проблема Алмаза.

Пример

  1. Предположим, что класс A имеет метод fun (). класс B и класс C происходят от класса A.
  2. И оба класса B и C переопределяют метод fun ().
  3. Теперь предположим, что класс D наследует и класс B, и C. (только предположение)
  4. Создать объект для класса D.
  5. D d = новый D ();
  6. и попробуйте получить доступ к d.fun (); => это будет вызывать веселье класса B () или веселье класса C? 

Это неоднозначность, существующая в алмазной проблеме.

Это не невозможно решить эту проблему, но это создает больше путаницы и сложностей для программиста при его чтении . Это вызывает больше проблем, чем пытается решить.

Примечание : Но в любом случае вы всегда можете реализовать множественное наследование косвенно, используя интерфейсы.

19
user1923551

Потому что у Java сильно отличается философия дизайна от C++. (Я не собираюсь обсуждать C # здесь.)

При разработке C++ Stroustrup хотел включить полезные функции, независимо от того, как они могут быть использованы не по назначению. Можно много обойтись с множественным наследованием, перегрузкой операторов, шаблонами и различными другими функциями, но с ними также можно делать очень хорошие вещи.

Философия дизайна Java состоит в том, чтобы подчеркнуть безопасность в языковых конструкциях. В результате есть вещи, которые гораздо более неловко делать, но вы можете быть намного увереннее, что код, который вы просматриваете, означает то, что, по вашему мнению, он делает.

Кроме того, Java была в значительной степени реакцией со стороны C++ и Smalltalk, самых известных OO языков. Существует множество других OO языков (на самом деле Common LISP был первым стандартизированным языком) с различными OO системами, которые лучше справляются с MI.

Не говоря уже о том, что вполне возможно сделать MI на Java, используя интерфейсы, композицию и делегирование. Он более явный, чем в C++, и, следовательно, более громоздкий в использовании, но даст вам то, что вы, скорее всего, поймете на первый взгляд.

Здесь нет правильного ответа. Есть разные ответы, и какой из них лучше для конкретной ситуации, зависит от приложений и индивидуальных предпочтений.

13
David Thornley

Основная (хотя и не единственная) причина, по которой люди избегают MI, - это так называемая «проблема с бриллиантами», приводящая к неопределенности в вашей реализации. Эта статья в Википедии обсуждает это и объясняет лучше, чем я мог. MI также может привести к более сложному коду, и многие разработчики OO утверждают, что MI вам не нужен, и если вы его используете, ваша модель, вероятно, ошибочна. Я не уверен, что согласен с этим последним пунктом, но держать вещи простыми - это всегда хороший план.

12
Steve Haigh

В C++ множественное наследование было основной головной болью при неправильном использовании. Чтобы избежать этих популярных проблем проектирования, в современных языках вместо «принудительного наследования» было задействовано несколько интерфейсов (Java, C #).

8
inazaruk

Множественное наследование

  • трудно понять 
  • сложность в отладке (например, если вы смешиваете классы из нескольких фреймворков, которые имеют методы с одинаковыми именами в глубине, может произойти довольно неожиданный синергизм)
  • легко неправильно использовать
  • не очень это полезно
  • сложно реализовать, особенно если вы хотите, чтобы это было сделано правильно и эффективно

Таким образом, это может считаться мудрым выбором, чтобы не включать множественное наследование в язык Java.

8
mfx

Другая причина в том, что одиночное наследование делает приведение тривиальным, не испуская инструкций ассемблера (кроме проверки совместимости типов, где это требуется). Если бы у вас было множественное наследование, вам нужно было бы выяснить, где в дочернем классе начинается определенный родительский класс. Таким образом, производительность, безусловно, является преимуществом (хотя и не единственным).

5
Blindy

Динамическая загрузка классов затрудняет реализацию множественного наследования.

На самом деле в Java они избежали сложности множественного наследования, используя единственное наследование и интерфейс. Сложность множественного наследования очень высока в ситуации, описанной ниже

алмазная проблема множественного наследования. У нас есть два класса B и C, наследуемых от A. Предположим, что B и C переопределяют унаследованный метод, и они предоставляют свою собственную реализацию. Теперь D наследует от B и C, делая множественное наследование. D должен наследовать этот переопределенный метод, JVM не может решить, какой переопределенный метод будет использоваться?

В c ++ виртуальные функции используются для обработки, и мы должны делать это явно.

Этого можно избежать, используя интерфейсы, нет методов тела. Интерфейсы не могут быть созданы - они могут быть реализованы только классами или расширены другими интерфейсами.

4
sujith s

В прежние времена (70-е годы), когда компьютерные науки были больше наукой и менее массовым производством, у программистов было время подумать о хорошем дизайне и хорошей реализации, и в результате продукты (программы) имели высокое качество (например, дизайн TCP/IP). и реализация). В настоящее время, когда все программируют, а менеджеры меняют спецификации до наступления крайних сроков, трудно отследить тонкие проблемы, подобные описанной в ссылке на википедию с поста Стива Хейга; поэтому «множественное наследование» ограничено конструкцией компилятора. Если вам это нравится, вы все равно можете использовать C++ .... и иметь всю свободу, какую пожелаете :) 

4
Cata Lin

Я принимаю утверждение, что «множественное наследование не разрешено в Java» с щепоткой соли.

Множественное наследование определяется, когда «Тип» наследуется от нескольких «Типов». И интерфейсы также классифицируются как типы, так как они имеют поведение. Так что Java имеет множественное наследование. Просто это безопаснее.

4
Rig Veda

На самом деле множественное наследование создаст сложность, если унаследованные классы имеют одинаковую функцию. т. е. у компилятора будет путаница, какой из них выбрать (проблема с алмазом). Таким образом, в Java эта сложность была устранена и предоставила интерфейс для получения функциональности, аналогичной множественному наследованию. Мы можем использовать интерфейс 

3
Jinu

У Java есть понятие, то есть полиморфизм. В Java существует 2 типа полиморфизма. Есть перегрузка метода и переопределение метода. Среди них переопределение методов происходит с отношениями супер- и подклассов. Если мы создаем объект подкласса и вызываем метод суперкласса, и если подкласс расширяет более одного класса, какой метод суперкласса должен быть вызван?

Или, при вызове конструктора суперкласса с помощью super(), какой конструктор суперкласса будет вызываться?

Это решение невозможно при использовании современных функций Java API. поэтому множественное наследование не разрешено в Java.

2
Abhay Kokate

Множественное наследование не разрешено в Java напрямую, но через интерфейсы это разрешено.

Причина: 

Множественное наследование: Вносит больше сложности и неоднозначности.

Интерфейсы: Интерфейсы - это полностью абстрактные классы в Java, которые предоставляют вам единый способ правильно разграничить структуру или внутреннюю работу вашей программы от ее общедоступного интерфейса, в результате чего повышается гибкость и возможность многократного использования кода по мере необходимости. а также больше контроля над тем, как вы создаете и взаимодействуете с другими классами. 

Точнее, они представляют собой специальную конструкцию в Java с дополнительной характеристикой, которая позволяет вам выполнять своего рода множественное наследование, то есть классы, которые могут быть переданы более чем в один класс.

Давайте возьмем простой пример.

  1. Предположим, что есть 2 класса суперклассов A и B с одинаковыми именами методов, но с разными функциями. В следующем коде с ключевым словом (extends) множественное наследование невозможно.

       public class A                               
         {
           void display()
             {
               System.out.println("Hello 'A' ");
             }
         }
    
       public class B                               
          {
            void display()
              {
                System.out.println("Hello 'B' ");
              }
          }
    
      public class C extends A, B    // which is not possible in Java
        {
          public static void main(String args[])
            {
              C object = new C();
              object.display();  // Here there is confusion,which display() to call, method from A class or B class
            }
        }
    
  2. Но через интерфейсы, с (реализует) ключевое слово множественное наследование возможно.

    interface A
        {
           // display()
        }
    
    
     interface B
        {
          //display()
        }
    
     class C implements A,B
        {
           //main()
           C object = new C();
           (A)object.display();     // call A's display
    
           (B)object.display(); //call B's display
        }
    }
    
1
Chaitra Deshpande

Кто-нибудь может сказать мне точно, почему это не разрешено?

Вы можете найти ответ из этой документации ссылка

Одна из причин, по которой язык программирования Java не позволяет расширять более одного класса, состоит в том, чтобы избежать проблем множественного наследования состояний, а именно способности наследовать поля от нескольких классов.

Если допускается множественное наследование и когда вы создаете объект путем создания экземпляра этого класса, этот объект будет наследовать поля от всех суперклассов класса. Это вызовет две проблемы.

  1. Что если методы или конструкторы из разных суперклассов создают одно и то же поле?

  2. Какой метод или конструктор будет иметь приоритет?

Даже если теперь разрешено множественное наследование состояний, вы все равно можете реализовать 

Множественное наследование типа: способность класса реализовывать более одного интерфейса.

Множественное наследование реализации (через методы по умолчанию в интерфейсах): Возможность наследовать определения методов от нескольких классов

Обратитесь к этому связанному вопросу SE для дополнительной информации:

Неоднозначность множественного наследования с интерфейсом

0
Ravindra babu

В C++ класс может наследовать (прямо или косвенно) от более чем одного класса, который называется множественное наследование .

C # и Java, однако, ограничивают классы одиночным наследованием, каждый класс наследует От одного родительского класса.

Множественное наследование - это полезный способ создания классов, которые объединяют аспекты двух разнородных иерархий классов .__, что часто случается при использовании различных структур классов в одном приложении. 

Например, если две платформы определяют свои собственные базовые классы для исключений, вы можете Использовать множественное наследование для создания классов исключений, которые можно использовать с любой инфраструктурой.

Проблема множественного наследования заключается в том, что это может привести к неоднозначности. Классический пример - когда Класс наследует от двух других классов, каждый из которых наследует от того же класса:

class A {
    protected:
    bool flag;
};
class B : public A {};
class C : public A {};
class D : public B, public C {
    public:
    void setFlag( bool nflag ){
        flag = nflag; // ambiguous
    }
};

В этом примере член данных flag определяется как class A. Но class D происходит от class B И class C, которые оба являются производными от A, поэтому по сути две копииflag доступны, потому что два Экземпляра A находятся в иерархии классов D. Какой из них вы хотите установить? Компилятор будет жаловаться , Что ссылка на flag в D является ambiguous. Одним из исправлений является явное устранение неоднозначности ссылки:

B::flag = nflag;

Другое исправление заключается в объявлении B и C как virtual base classes, что означает, что в иерархии может существовать только одна копия A .__, устраняя любую неопределенность.

Существуют и другие сложности с множественным наследованием, например, порядок, в котором базовые классы Инициализируются при создании производного объекта, или способ непреднамеренного скрытия членов .__ от производных классов. Чтобы избежать этих сложностей, некоторые языки ограничиваются более простой моделью одиночного наследования.

Хотя это значительно упрощает наследование, оно также ограничивает его полезность , Поскольку только классы с общим предком могут иметь общее поведение. Интерфейсы несколько смягчают это ограничение , Позволяя классам в разных иерархиях предоставлять общие интерфейсы даже , Если они не реализованы путем совместного использования кода.

0
zerocool