Когда класс X наследует от другого класса Y, это имеет два эффекта:
- Класс X получает реализации по умолчанию для большей части или всех функциональных возможностей класса Y и, таким образом, должен только определять для себя вещи, которые отличаются от класса Y.
- Объект класса X можно использовать практически везде, где можно использовать объект класса Y.
Наследование является очень мощным, но имеет фундаментальное ограничение: каждый класс, кроме Object, должен быть производным точно от одного другого класса. Если наследование было единственным средством, с помощью которого объект одного типа мог бы заменить другой тип, это означало бы, что единственный способ, которым один тип мог бы заменить два или более супертипов, был бы, если бы один из этих супертипов сам мог бы заменить другой. , К сожалению, есть много ситуаций, в которых отношения типов не образуют хорошую иерархию. Например, в графической программе можно захотеть иметь возможность рассматривать как FilledRectangle, так и FilledEllipse как заменяемые для FilledShape, и рассматривать как FilledEllipse и OutlineEllipse как заменяемые для EllipseShape, но для этого требуется, чтобы FilledEllipse заменял оба FilledShape и EllipseShape, хотя ни один из них не может заменить другой.
Интерфейсы обходят это ограничение, предоставляя средство, с помощью которого тип может объявить себя заменяемым для многих других типов (интерфейсов) без необходимости наследования от них. Например, в приведенном выше графическом примере может быть интерфейс IFilledShape с такими элементами, как FillColor, и интерфейс IEllipseShape с такими элементами, как SetCenter, GetMajorAxis и т. Д. Если подпрограмма ожидает параметр типа IFilledShape, можно передать в FilledRectangle, FilledEllipse, FilledTriangle или любой другой тип, который реализует IFilledShape. Тот факт, что FilledEllipse реализует IFilledShape, не мешает ему также реализовывать IEllipseShape или IDrawableShape или любой другой интерфейс.