В чем разница между подтипированием и наследованием в программировании OO?
Я не мог найти главного отличия. И я очень смущен, когда мы можем использовать наследование и когда мы можем использовать подтипирование. Я нашел некоторые определения, но они не очень понятны.
В чем разница между подтипированием и наследованием в объектно-ориентированном программировании?
Ответы
Ответ 1
В дополнение к уже даным ответам, здесь ссылка на статью, я думаю, является актуальной. Выдержки:
В объектно-ориентированной среде наследование обычно представляется как функция, которая идет рука об руку с подтипами, когда кто-то организует абстрактные типы данных в иерархии классов. Тем не менее, эти два являются ортогональными идеями.
- Подтип относится к совместимости интерфейсов. Тип
B
является подтипом A
если каждая функция, которая может быть вызвана для объекта типа A
также может быть вызвана для объекта типа B
- Наследование относится к повторному использованию реализаций. Тип
B
наследуется от другого типа A
если некоторые функции для B
написаны в терминах функций из A
Однако подтипирование и наследование не должны идти рука об руку. Рассмотрим структуру данных deque, двустороннюю очередь. Deque поддерживает вставку и удаление на обоих концах, поэтому он имеет четыре функции: insert-front
, delete-front
, insert-rear
и delete-rear
. Если мы используем просто insert-rear
и delete-front
мы получим обычную очередь. С другой стороны, если мы используем просто insert-front
и delete-front
, мы получаем стек. Другими словами, мы можем реализовать очереди и стеки в терминах deques, так что типы данных, Stack
и Queue
наследуются от Deque
. С другой стороны, ни Stack
ни Queue
являются подтипами Deque
поскольку они не поддерживают все функции, предоставляемые Deque
. Фактически, в этом случае Deque
является подтипом и Stack
и Queue
!
Я думаю, что Java, C++, С# и им подобные способствовали путанице, как уже отмечалось, тем фактом, что они объединяют обе идеи в единую иерархию классов. Тем не менее, я думаю, что приведенный выше пример отдает должное идеям довольно не зависящим от языка образом. Я уверен, что другие могут привести больше примеров.
Ответ 2
Относительно, к сожалению, умер и оставил вам свой книжный магазин.
Теперь вы можете читать все книги, продавать их, просматривать свои учетные записи, список своих клиентов и т.д. Это наследование - у вас есть все, что имеет родственник. Наследование - это форма повторного использования кода.
Вы также можете заново открыть книжный магазин самостоятельно, взяв на себя все относительные роли и обязанности, даже если вы добавите свои собственные изменения - это подтипирование - теперь вы являетесь книжным магазином владелец, как и раньше.
Подтипирование является ключевым компонентом ООП - у вас есть объект одного типа, но который выполняет интерфейс другого типа, поэтому его можно использовать везде, где мог использоваться другой объект.
В языках, перечисленных в вашем вопросе - С++, Java и С# - эти два (почти) всегда используются вместе, и, таким образом, единственный способ унаследовать от чего-либо - это подтип его и наоборот. Но другие языки не обязательно сливают эти два понятия.
Ответ 3
Наследование - это получение атрибутов (и/или функциональных возможностей) супер-типов. Например:
class Base {
//interface with included definitions
}
class Derived inherits Base {
//Add some additional functionality.
//Reuse Base without having to explicitly forward
//the functions in Base
}
Здесь Derived
не может использоваться там, где ожидается Base
, но он может действовать аналогично Base
, добавляя поведение или изменяя некоторый аспект поведения Base
. Как правило, Base
будет небольшим вспомогательным классом, который обеспечивает как интерфейс, так и реализацию для некоторых обычно требуемых функций.
Подтип-полиморфизм связан с реализацией интерфейса и тем самым может заменить различные реализации этого интерфейса во время выполнения:
class Interface {
//some abstract interface, no definitions included
}
class Implementation implements Interface {
//provide all the operations
//required by the interface
}
Здесь Implementation
можно использовать везде, где требуется Interface
, и во время выполнения могут быть заменены различные реализации. Цель состоит в том, чтобы более широко использовать код, который использует Interface
.
Ваше замешательство оправдано. Java, С# и С++ объединяют эти две идеи в одну иерархию классов. Однако эти два понятия не идентичны, и существуют языки, которые разделяют два.
Ответ 4
Если вы наследуете конфиденциально в C++, вы получаете наследование без подтипов. То есть дано:
class Derived : Base // note the missing public before Base
Вы не можете написать:
Base * p = new Derived(); // type error
Потому что Derived
не является подтипом Base
. Вы просто унаследовали реализацию, а не тип.
Ответ 5
одним словом: подтип и наследование - это полиморфизм (наследование - это динамический полиморфизм - переопределение). На самом деле наследование является подклассом, это означает, что в наследовании нет гарантии для обеспечения возможности подкласса с суперклассом (убедитесь, что подкласс не отбрасывает поведение суперкласса), но подтип (такой как реализация интерфейса и...), обеспечивает класс не отбрасывает ожидаемое поведение.
Ответ 6
Подтипирование не должно быть реализовано через наследование. Некоторый подтип, который не является наследованием:
- Ocaml вариант
- Ржавчина аннотации
- Чистые типы уникальности
- Перейти интерфейс