Взгляд на подтипы
Тип - это не просто множество объектов. Он характеризуется также применимыми операциями (компонентами) и их семантическими свойствами (утверждениями: предусловиями, постусловиями, инвариантами). Мы предполагаем, что компоненты и утверждения наследника совместимы с концепцией подтипа, означая, что любой экземпляр наследника должен рассматриваться также как экземпляр родителя.
Правила, применяемые к утверждениям, поддерживают этот взгляд на подтипы:
- инвариант родителя автоматически является частью инварианта наследника, так что все ограничения, специфицированные для экземпляров родителя, применимы к экземплярам родителя;
- предусловие подпрограмм, возможно ослабленное, применимо к любому ее переопределению у потомка, так что любой вызов, удовлетворяющий требованиям для экземпляров родителя, будет также удовлетворять требованиям экземпляров наследника;
- постусловие подпрограмм, возможно, усиленное, применимо к любому ее переопределению у потомка, так что любое свойство на выходе подпрограммы, специфицированное для экземпляра родителя, будет также выполняться экземплярами наследника.
Для компонентов ситуация более тонкая. С точки зрения на подтип требуется, чтобы все операции, применимые к экземплярам родителя, должны быть применимы к экземплярам наследника. Внутренне это всегда верно: даже для класса ARRAYED_STACK, наследуемого от ARRAY, который, кажется, далек от наследования подтипов, компоненты ARRAY доступны наследнику и фактически являлись основой для реализаций свойств стека. Но в этом случае мы скрываем все эти компоненты ARRAY от клиентов наследника по вполне разумным причинам (мы не хотим, чтобы клиенты могли выполнять операции, зависящие от внутреннего представления, так как это бы нарушало интерфейс класса).
Для чистого наследования подтипов можно предложить более сильное правило: каждый компонент, применимый клиентом к экземплярам родительского класса, тем же клиентом может быть применен к экземплярам наследника. Другими словами, нет скрытия компонента потомком: если B наследует f от A, то статус экспорта f в B не менее широкий, чем в A. (Так что общеэкспортируемый компонент f таковым и остается, а выборочно экспортируемый может только расширить круг клиентов.)