2009-06-15 4 views
93

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

+1

Так же, как чтобы указать, что существуют * рамки, которые позволяют MI-подобное поведение в классах C#. И, конечно, у вас есть возможность иметь безстоящие микшины (используя методы расширения) - будучи апатридом, они не очень полезны. –

+0

Эти интерфейсы имеют какое-либо отношение к наследованию, это иллюзия, созданная синтаксисом языка. Наследование должно сделать вас богаче. Ничего подобного для интерфейса, вы не наследуете приседания, и это делает вас значительно хуже. Вы унаследовали долги азартных игр дяди Гарри, у вас есть больше работы, чтобы реализовать интерфейс. –

ответ

128

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

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

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

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

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

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

You can read the full article here.

Для Java, вы можете прочитать this article:

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

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

+8

Хорошее сравнение. Я считаю, что я думаю о процессах мышления, которые лежат в основе обеих платформ. – CurtainDog

12

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

81

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

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

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

+3

двойной бриллиант - это пиво! ;) –

+71

Вы получаете прекрасную акварель кого-то мертвого на улице :-) –

+0

Это единственная проблема? Я думаю, я не уверен, что C++ решает эту проблему с помощью ключевого слова virtual, это правда? Я плохо разбираюсь в C++ –

8

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

5

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

3

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

+4

... включая свободу стрелять в ногу, несколько раз;) –

4

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

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

+6

Но вы не наследуете интерфейс, вы его реализуете. Интерфейсы не являются классами. – Blorgbeard

+2

Да, но наследование никогда не было так узко определено, за исключением некоторых книг о предисловии. И я думаю, что мы должны смотреть за пределы его грамматики. Они оба делают то же самое, и интерфейсы были «изобретены» только для . –

+0

Удерживание для удаления -1. У вас есть хороший момент. –

8

множественного наследование

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

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

+2

Я не согласен со всем вышеперечисленным, работая с Common Lisp Object System. –

+1

Динамические языки не считаются ;-) В любой Lisp-подобной системе у вас есть REPL, что делает отладку довольно простой. Кроме того, CLOS (как я понимаю, я никогда не использовал его, только читал об этом) представляет собой метаобъектную систему с большой гибкостью и рутингом. Но рассмотрим статически скомпилированный язык, такой как C++, где компилятор генерирует какой-либо дьявольски сложный поиск метода с использованием нескольких (возможно перекрывающихся) vtables: в такой реализации выяснение того, какая реализация метода была вызвана, может быть не столь тривиальной задача. – mfx

13

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

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

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

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

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

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

3

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

Или, вызывая конструктор суперкласса на super(), который вызовет суперкласс класса?

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

+0

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

4

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

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

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

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

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

17

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

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

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

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

Пример:

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

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

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

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

3

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

1

Множественное наследование не допускается непосредственно в 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 
        } 
    } 
    
-3

Представьте себе этот пример: У меня есть класс Shape1

имеет CalcualteArea метод:

Class Shape1 
{ 

public void CalculateArea() 

    { 
     // 
    } 
} 

Существует еще один класс Shape2, что один имеет тот же метод

Class Shape2 
{ 

public void CalculateArea() 

    { 

    } 
} 

Теперь у меня есть дочерний класс Circle, он происходит как от Shape1, так и от Shape2;

public class Circle: Shape1, Shape2 
{ 
} 

Теперь, когда я создаю объект для Circle и вызываю метод, система не знает, какой метод вычисляемой области будет вызываться. Оба имеют одинаковые подписи. Поэтому компилятор запутается. Вот почему множественные наследования не допускаются.

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

+0

Разработчик языка может дать явный вызов метода, как в интерфейсе. Такого смысла нет! Другая причина заключается в том, как теперь абстрактный класс с абстрактными методами, как вы это считаете? –

0

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

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

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

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

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

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

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

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

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

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

Multiple Inheritance Ambiguity with Interface

Смежные вопросы