stringtranslate.com

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

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

Множественное наследование было спорным вопросом в течение многих лет, [1] [2] с оппонентами, указывающими на его возросшую сложность и неоднозначность в таких ситуациях, как «проблема алмаза», где может быть неоднозначно, от какого родительского класса унаследована конкретная функция, если более одного родительского класса реализуют эту функцию. Это можно решить разными способами, включая использование виртуального наследования . [3] Для решения неоднозначности также были предложены альтернативные методы композиции объектов, не основанные на наследовании, такие как миксины и черты .

Подробности

В объектно-ориентированном программировании (ООП) наследование описывает связь между двумя классами, в которой один класс ( дочерний класс) подклассифицирует родительский класс . Дочерний класс наследует методы и атрибуты родителя, что позволяет использовать общую функциональность. Например, можно создать переменный класс Mammal с такими функциями, как прием пищи, размножение и т. д.; затем определить дочерний класс Cat , который наследует эти функции без необходимости явно их программировать, добавляя при этом новые функции, такие как преследование мышей .

Множественное наследование позволяет программистам использовать более одной полностью ортогональной иерархии одновременно, например, позволяя классу Cat наследовать от Cartoon Character , Pet и Mammal и получать доступ к функциям из всех этих классов.

Реализации

Языки, которые поддерживают множественное наследование, включают: C++ , Common Lisp (через Common Lisp Object System (CLOS)), EuLisp (через EuLisp Object System TELOS), Curl , Dylan , Eiffel , Logtalk , Object REXX , Scala (через использование классов- миксинов ), OCaml , Perl , POP-11 , Python , R , Raku и Tcl (встроенный с версии 8.6 или через Incremental Tcl ( Incr Tcl ) в более ранних версиях [4] [5] ).

Среда выполнения IBM System Object Model (SOM) поддерживает множественное наследование, и любой язык программирования, ориентированный на SOM, может реализовывать новые классы SOM, унаследованные от нескольких баз.

Некоторые объектно-ориентированные языки, такие как Swift , Java , Fortran с момента его ревизии 2003 года , C# и Ruby , реализуют одиночное наследование , хотя протоколы или интерфейсы предоставляют некоторые функции настоящего множественного наследования.

PHP использует классы признаков для наследования конкретных реализаций методов. Ruby использует модули для наследования нескольких методов.

Проблема алмазов

Диаграмма наследования класса алмазов.

« Проблема алмаза » (иногда называемая «смертельным алмазом смерти» [6] ) — это неоднозначность, которая возникает, когда два класса B и C наследуют от A, а класс D наследует как от B, так и от C. Если в A есть метод, который B и C переопределили , а D не переопределяет его, то какую версию метода наследует D: от B или от C?

Например, в контексте разработки программного обеспечения GUI класс может наследовать от обоих классов (для внешнего вида) и (для функциональности/обработки ввода), а классы и оба наследуют от класса. Теперь, если метод вызывается для объекта и такого метода нет в классе, но есть переопределенный метод в или (или в обоих), какой метод должен быть в конечном итоге вызван?ButtonRectangleClickableRectangleClickableObjectequalsButtonButtonequalsRectangleClickable

Это называется «проблемой ромба» из-за формы диаграммы наследования классов в этой ситуации. В этом случае класс A находится наверху, B и C по отдельности под ним, а D объединяет их вместе внизу, образуя форму ромба.

Смягчение

В разных языках существуют разные способы решения проблем повторного наследования.

Языки, которые допускают только одиночное наследование , где класс может быть производным только от одного базового класса, не имеют проблемы алмаза. Причина этого в том, что такие языки имеют максимум одну реализацию любого метода на любом уровне в цепочке наследования независимо от повторения или размещения методов. Обычно эти языки позволяют классам реализовывать несколько протоколов , называемых интерфейсами в Java. Эти протоколы определяют методы, но не предоставляют конкретных реализаций. Эта стратегия использовалась ActionScript , C# , D , Java , Nemerle , Object Pascal , Objective-C , Smalltalk , Swift и PHP . [13] Все эти языки позволяют классам реализовывать несколько протоколов.

Более того, Ada , C#, Java, Object Pascal, Objective-C, Swift и PHP допускают множественное наследование интерфейсов (называемых протоколами в Objective-C и Swift). Интерфейсы подобны абстрактным базовым классам, которые определяют сигнатуры методов, не реализуя никакого поведения. («Чистые» интерфейсы, такие как в Java до версии 7, не допускают никакой реализации или данных экземпляра в интерфейсе.) Тем не менее, даже когда несколько интерфейсов объявляют одну и ту же сигнатуру метода, как только этот метод реализуется (определяется) где-либо в цепочке наследования, он переопределяет любую реализацию этого метода в цепочке выше (в его суперклассах). Следовательно, на любом заданном уровне в цепочке наследования может быть не более одной реализации любого метода. Таким образом, реализация метода с одиночным наследованием не демонстрирует проблему Diamond даже при множественном наследовании интерфейсов. С введением реализации по умолчанию для интерфейсов в Java 8 и C# 8 все еще возможно сгенерировать проблему Diamond, хотя это будет выглядеть только как ошибка времени компиляции.

Смотрите также

Ссылки

  1. ^ Каргилл, ТА (зима 1991 г.). «Противоречие: аргументы против множественного наследования в C++». Вычислительные системы . 4 (1): 69–82.
  2. ^ Уолдо, Джим (весна 1991 г.). «Противоречие: аргументы в пользу множественного наследования в C++». Computing Systems . 4 (2): 157–171.
  3. ^ Шерли, Натанаэль; Дюкасс, Стефан; Ниерштрас, Оскар; Блэк, Эндрю. «Черты: составные единицы поведения» (PDF) . Web.cecs.pdx.edu . Получено 21 октября 2016 г.
  4. ^ "incr Tcl". blog.tcl.tk . Получено 2020-04-14 .
  5. ^ "Введение в язык программирования Tcl". www2.lib.uchicago.edu . Получено 14.04.2020 .
  6. ^ Мартин, Роберт С. (1997-03-09). "Java и C++: критическое сравнение" (PDF) . Objectmentor.com . Архивировано из оригинала (PDF) 2005-10-24 . Получено 2016-10-21 .
  7. ^ "Стандарт ECMA-367". Ecma-international.org . Получено 21 октября 2016 г. .
  8. ^ "Состояние лямбды". Cr.openjdk.java.net . Получено 21.10.2016 .
  9. ^ "perlobj". perldoc.perl.org . Получено 2016-10-21 .
  10. ^ Аннотация. "Порядок разрешения методов Python 2.3". Python.org . Получено 21.10.2016 .
  11. ^ "Унификация типов и классов в Python 2.2". Python.org . Получено 2016-10-21 .
  12. ^ "Manpage of class". Tcl.tk . 1999-11-16 . Получено 2016-10-21 .
  13. ^ "Object Interfaces - Manual". PHP.net . 2007-07-04 . Получено 2016-10-21 .

Дальнейшее чтение

Внешние ссылки