Подтвердить что ты не робот

Когда многократное наследование пригодится?

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

Когда нужно использовать множественное наследование?

Почему некоторые языки поддерживают множественное наследование (С++, Python), а другие нет (Java, Ruby)? Я имею в виду - на основе каких факторов создатели языков программирования решают включить поддержку MI или нет.

4b9b3361

Ответ 1

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

Что касается примеров,

Из личного опыта множественное наследование может быть весьма полезным, но это также может быть большой проблемой легко. На странице Википедии в какой-то степени рассматривается проблема алмаза: сводится к вопросу о том, что должно произойти, если два или более базовых класса обеспечивают реализацию какого-либо метода. Языки должны определить/реализовать способ справиться с этим, как правило, путем определения порядка разрешения порядка (например, Python mro).

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

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

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

Ответ 2

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

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

Здесь - ссылка на часто задаваемый вопрос в MSDN, который объясняет, почему С# не поддерживает множественное наследование.

Ответ 3

Пример реального мира: я столкнулся с одной ситуацией, когда многократное наследование действительно имело большой смысл, это для реализации С++ Векторный анимационный комплекс.

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

  • вершины + ребра + грани в пространственной области
  • ключи + inbetweens во временном домене

Поскольку структура данных является перекрестным продуктом между пространством и временем, у вас всего 6 классов:

  • KeyVertex
  • KeyEdge
  • KeyFace
  • InbetweenVertex
  • InbetweenEdge
  • InbetweenFace

Способ, которым я его реализовал, - это множественное наследование. Существует виртуальный базовый класс:

class Cell; 

Затем существуют три виртуальных класса для реализации "пространственного поведения" этих ячеек и двух виртуальных классов для реализации "временного поведения":

class VertexCell:    virtual public Cell; 
class EdgeCell:      virtual public Cell; 
class FaceCell:      virtual public Cell; 

class KeyCell:       virtual public Cell; 
class InbetweenCell: virtual public Cell; 

Наконец, фактические не виртуальные классы определяются с множественным наследованием:

class KeyVertex:       public KeyCell,       public VertexCell; 
class KeyEdge:         public KeyCell,       public EdgeCell; 
class KeyFace:         public KeyCell,       public FaceCell; 
class InbetweenVertex: public InbetweenCell, public VertexCell; 
class InbetweenEdge:   public InbetweenCell, public EdgeCell; 
class InbetweenFace:   public InbetweenCell, public FaceCell; 

В дополнение к понятию математически и концептуально это имело два практических преимущества:

  • Максимальный общий код. Обмен кодами также может быть достигнут с составом, но для этого потребовалось бы больше шаблонов.

  • Литье в базовые классы. Иногда мне нужен большой контейнер для управления всеми ячейками, поэтому отлично, что все они наследуют Cell, так как я могу иметь vector<Cell*> и напрямую вызывать виртуальные методы, общие для всех ячеек (например, draw()). Иногда мне нужен vector<VertexCell*>. Иногда мне нужен vector<KeyCell*>.

Фактически, я даже написал удобные контейнеры, чтобы я мог делать такие вещи, как:

CellPtrSet cells = getCells();
KeyCellPtrSet keyCells = cells; // Cast and copy those which are actually key cells

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

Ответ 4

Примерами современных языков, поддерживающих множественное наследование, являются Java и Scala. Java имеет методы интерфейса по умолчанию, поскольку Java8 и Scala имеют черты, которые могут содержать методы и данные.

Теперь примеры использования:

  • Определите полезные методы, которые вызывают абстрактные методы. Например, Collection.removeIf в Java - он удаляет элементы на основе предоставленного предиката. Таким образом, каждый класс, реализующий Collection, будет иметь метод removeIf.
  • Разделить класс с множеством публичных методов на меньшие единицы кода. Бывают случаи, когда агрегация не работает, и нам действительно нужны полсотни общедоступных методов в одном классе. Множественное наследование позволяет лучше управлять таким кодом.
  • DSL. Вы можете добавить DSL в свой код, наследуя от класса, который реализует этот DSL.
  • Добавьте какое-то поведение к своим объектам. В С++ вы можете использовать множественное наследование, чтобы добавить счетчик ссылок к каждому объекту для управления памятью.

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

Ответ 5

MI или множественное наследование - очень общая тема для обсуждения, будьте осторожны, о чем вы просите... Я попытаюсь дать вам короткий ответ, как сказал однажды мой профессор, "наследование моделирует реальную жизнь, когда ваш объект в реальной жизни наследует черты, а также ваши объекты". в конце дня вы должны подумать о программисте, который использует ваш класс, нужно ли ему знать ваши составные объекты? или, может быть, лучше он просто вызовет функции "закрытого ящика". лучший пример - стиральная машина, у нее есть кнопки и много стиральных функций, но вам все равно, что происходит внутри, так и ваш класс, если я его использую, мне не нужно знать объекты, которые делают его просто функции. было бы еще лучше, если бы я знал только интерфейс.

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

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