Java пропускает множественное наследование на том основании, что она устраняет цель разработки - сделать язык простым .
Интересно, действительно ли Java (с ее эко-системой) "проста"? Python не сложен и имеет множественное наследование. Итак, не будучи слишком субъективным, мой вопрос ...
Каковы типичные шаблоны проблем, которые выигрывают от кода, разработанного для интенсивного использования множественного наследования
multiple-inheritance
treecoder
источник
источник
Ответы:
Плюсы:
Минусы:
В C ++ хорошим примером множественного наследования, используемого для составления ортогональных функций, является случай, когда вы используете CRTP , например, для установки системы компонентов для игры.
Я начал писать пример, но думаю, что пример из реального мира стоит посмотреть. Некоторый код Ogre3D использует множественное наследование приятным и очень интуитивно понятным способом. Например, класс Mesh наследуется от ресурсов и AnimationContainer. Ресурсы предоставляют интерфейс, общий для всех ресурсов, а AnimationContainer - интерфейс, специфичный для управления набором анимаций. Они не связаны между собой, поэтому легко представить себе Mesh как ресурс, который, кроме того, может содержать набор анимаций. Чувствует себя естественно, не так ли?
Вы можете взглянуть на другие примеры в этой библиотеке , например, на способ, которым распределение памяти управляется в тончайшем порядке, делая классы наследующими от вариантов CRTP-класса, перегружающих new и delete.
Как уже говорилось, основные проблемы с множественным наследованием возникают из-за смешения связанных понятий. Это заставляет язык устанавливать сложные реализации (см., Как C ++ позволяет играть с проблемой алмаза ...), и пользователь не уверен, что происходит в этой реализации. Например, прочитайте эту статью, объясняющую, как это реализовано в C ++ .
Удаление этого из языка помогает избежать людей, которые не знают, как язык используется, чтобы сделать вещи плохими. Но это заставляет думать так, что иногда это не кажется естественным, даже если это крайние случаи, это случается чаще, чем вы могли бы подумать.
источник
Существует концепция, называемая миксинами, которая интенсивно используется в более динамичных языках. Множественное наследование - это один из способов, с помощью которого миксины могут поддерживаться языком. Миксины, как правило, используются в классе для накопления различных частей функциональности. Без множественного наследования вы должны использовать агрегацию / делегирование, чтобы получить поведение типа mixin с классом, который немного тяжелее синтаксиса.
источник
Я думаю, что выбор в основном основан на проблемах, связанных с проблемой алмазов .
Кроме того, часто можно обойти использование множественного наследования путем делегирования или другими способами.
Я не уверен в значении вашего последнего вопроса. Но если это «в каких случаях полезно множественное наследование?», То во всех случаях, когда вы хотите, чтобы объект A имел функциональные возможности объектов B и C, в основном.
источник
Я не буду здесь углубляться в подробности, но вы наверняка сможете понять множественное наследование в python по следующей ссылке http://docs.python.org/release/1.5.1p1/tut/multiple.html :
...
Это всего лишь маленький абзац, но достаточно большой, чтобы очистить сомнения, я думаю.
источник
Единственное место, где было бы полезно множественное наследование, - это ситуация, когда класс реализует несколько интерфейсов, но вы хотели бы иметь некоторые функциональные возможности по умолчанию, встроенные в каждый интерфейс. Это полезно, если большинство классов, которые реализуют некоторый интерфейс, хотят делать что-то одинаково, но иногда вам нужно делать что-то другое. Вы можете иметь каждый класс с одинаковой реализацией, но имеет больше смысла помещать его в одно место.
источник
Это всего лишь один пример, но я считаю, что он неоценим для повышения безопасности и снижения соблазна применять каскадные изменения в вызывающих или подклассах.
Я обнаружил, что множественное наследование невероятно полезно даже для самых абстрактных интерфейсов без сохранения состояния - это идиома невиртуального интерфейса (NVI) в C ++.
Они даже не настолько абстрактные базовые классы, сколько интерфейсы, которые имеют лишь небольшую реализацию для реализации универсальных аспектов своих контрактов, так как они на самом деле не сужают универсальность контракта, а улучшают его соблюдение. ,
Простой пример (некоторые могут проверить, что переданный дескриптор файла открыт или что-то в этом роде):
В этом случае, возможно,
f
вызывается тысячей мест в кодовой базе, аf_impl
переопределяется сотней подклассов.Было бы трудно выполнить такую проверку безопасности во всех 1000 местах, которые вызывают,
f
или во всех 100 местах, которые переопределяютf_impl
.Просто делая эту точку входа в функциональность не виртуальной, это дает мне одно центральное место для выполнения этой проверки. И эта проверка ни в коей мере не уменьшает абстракцию, поскольку она просто устанавливает предварительное условие, необходимое для вызова этой функции. В некотором смысле это возможно укрепляет контракт, предоставляемый интерфейсом, и облегчает бремя проверки
x
входных данных, чтобы убедиться, что они соответствуют действительным предварительным условиям во всех 100 местах, которые переопределяют его.Это то, чего я желал бы иметь каждый язык, а также желал, даже в C ++, чтобы это было немного больше нативной концепции (например: не требовать от нас определения отдельной функции для переопределения).
Это чрезвычайно полезно, если вы не сделали этого
assert
заранее и поняли, что вам это нужно позже, когда некоторые случайные места в кодовой базе сталкиваются с передаваемыми отрицательными значениямиf
.источник
Во-первых: несколько копий базового класса (проблема C ++) и тесная связь между базовыми и производными классами.
Второе: множественное наследование от абстрактных интерфейсов
источник