Я не парень C ++, но я вынужден думать об этом. Почему множественное наследование возможно в C ++, но не в C #? (Я знаю о проблеме алмазов , но я не об этом здесь спрашиваю). Как C ++ разрешает неоднозначность идентичных сигнатур методов, унаследованных от нескольких базовых классов? И почему тот же дизайн не включен в C #?
c#
c++
language-design
multiple-inheritance
Sandeep
источник
источник
Ответы:
Я думаю (не имея точных ссылок), что в Java они хотели ограничить выразительность языка, чтобы облегчить его изучение, и потому что код, использующий множественное наследование, чаще всего слишком сложен для своего блага, чем нет. А поскольку полное множественное наследование намного сложнее в реализации, оно значительно упростило и виртуальную машину (множественное наследование особенно плохо взаимодействует со сборщиком мусора, поскольку требует хранения указателей на середину объекта (в начале базы). )
И при разработке C # я думаю, что они смотрели на Java, увидели, что полное множественное наследование действительно не так уж и упущено, и решили сделать все проще.
Это не так . Существует синтаксис для вызова метода базового класса из конкретной базы в явном виде, но нет способа переопределить только один из виртуальных методов, и если вы не переопределите метод в подклассе, его невозможно вызвать без указания базы учебный класс.
Там нет ничего, чтобы включить.
Поскольку Джорджио упомянул методы расширения интерфейса в комментариях, я объясню, что такое миксины и как они реализованы на разных языках.
Интерфейсы в Java и C # ограничены только объявлением методов. Но методы должны быть реализованы в каждом классе, который наследует интерфейс. Однако существует большой класс интерфейсов, где было бы полезно предоставить реализации некоторых методов по умолчанию в терминах других. Типичный пример сопоставим (на псевдо-языке):
Отличие от полного класса в том, что он не может содержать никаких элементов данных. Есть несколько вариантов реализации этого. Очевидно, множественное наследование одно. Но множественное наследование довольно сложно реализовать. Но это действительно не нужно здесь. Вместо этого многие языки реализуют это, разделяя миксин в интерфейсе, который реализуется классом, и в хранилище реализаций методов, которые либо внедряются в сам класс, либо генерируется промежуточный базовый класс, и они размещаются там. Это реализовано в Ruby и D , будет реализовано в Java 8 и может быть реализовано вручную в C ++ с использованием любопытно повторяющегося шаблона . Выше, в форме CRTP, выглядит так:
и используется как:
Для этого не требуется ничего объявлять виртуальным, как это делает обычный базовый класс, поэтому, если интерфейс используется в шаблонах, остаются открытыми полезные параметры оптимизации. Обратите внимание, что в C ++ это, вероятно, все еще будет наследоваться как второй родитель, но в языках, которые не допускают множественное наследование, оно вставляется в единую цепочку наследования, так что это больше похоже на
Реализация компилятора может или не может избежать виртуальной диспетчеризации.
В C # была выбрана другая реализация. В C # реализации являются статическими методами совершенно отдельного класса, и синтаксис вызова метода соответствующим образом интерпретируется компилятором, если метод с данным именем не существует, но определен «метод расширения». Это имеет преимущество в том, что методы расширения могут быть добавлены к уже скомпилированному классу, и недостаток в том, что такие методы не могут быть переопределены, например, для обеспечения оптимизированной версии.
источник
Ответ заключается в том, что он не работает правильно в C ++ в случае столкновений пространства имен. Смотрите это . Чтобы избежать столкновения пространства имен, вы должны выполнять все виды вращений с указателями. Я работал в MS в команде Visual Studio и, по крайней мере, отчасти потому, что они разработали делегирование, заключались в том, чтобы вообще избежать коллизий пространства имен. Ранее я говорил, что они также считают интерфейсы частью решения множественного наследования, но я ошибся. Интерфейсы действительно удивительны и могут работать на C ++, FWIW.
В частности, делегирование устраняет коллизию пространства имен: вы можете делегировать до 5 классов, и все 5 из них будут экспортировать свои методы в вашу область как члены первого класса. Наружный взгляд на это - множественное наследование.
источник