Теперь о различиях.
Итак, сначала о сходстве.
Как в абстрактных классах, так и в интерфейсах допускается наличие членов, которые могут наследоваться производными классами. Ни абстрактные классы, ни интерфейсы не допускают непосредственного создания экземпляров, хотя мы можем объявлять переменные соответствующих типов. В этом случае можно использовать полиморфизм при присваивании объектов, которые наследуются от этих типов, переменным таких типов. В обоих случаях мы получаем возможность использовать члены этих типов с помощью этих переменных, хотя и не имеем непосредственного доступа к другим членам производного класса.
Производные классы могут наследоваться только от одного базового класса, что означает, что непосредственно наследоваться может только один абстрактный класс (хотя вся цепочка наследования может включать в себя несколько абстрактных классов). Напротив, классы могут использовать произвольное количество интерфейсов. Отличие, однако, не столь уж существенно: результаты в обоих случаях приблизительно одинаковы. При использовании интерфейсов все оказывается несколько иначе.
У абстрактных классов могут быть как абстрактные члены (у которых отсутствует тело программы и которые обязательно должны реализоваться в производных классах, если производный класс сам, в свою очередь, не является абстрактным), так и неабстрактные члены (которые обладают телом программы и могут быть виртуальными, т. е. могут переопределяться в производных классах). С другой стороны, все члены интерфейса должны быть реализованы в классе, который использует данный интерфейс,— ни у одного из них нет тела программы. Кроме того, все члены интерфейса являются по определению общими (поскольку предназначаются для внешнего использования), а члены абстрактного класса могут быть и частными (когда доступ к защищенным внутренним членам осуществляется исключительно из кода, находящегося внутри приложения, или из производного класса). Помимо этого, интерфейсы не могут иметь полей, конструкторов, деструкторов, статических членов и констант.
Это указывает на то, что эти два типа предназначаются для совершенно различных целей. Абстрактные классы используются в качестве базовых классов семейств тех объектов, которые обладают общими основными характеристиками, такими как цели, для которых они предназначены, и структура. Интерфейсы используются классами, отличия между которыми могут лежать на гораздо более фундаментальном уровне, но которым при этом может требоваться выполнение некоторых одинаковых действий. В качестве примера представьте себе семейство объектов, представляющих поезда (см. рис. слева).
Базовый класс — Train (поезд) — содержит основное определение поезда, куда включается, например, размер колес и тип двигателя (который может быть паровым, дизельным и т . д . ) . Этот класс, однако, является абстрактным, поскольку в природе не существует такой вещи, как "обобщенный" поезд. Для создания "конкретного" поезда нужно задать характеристики, присущие данному поезду. Это, в свою очередь, требует создания производных классов вроде PassengerTrain (пассажирский поезд), FreightTrain (грузовой поезд) и 424DoubieBogey (424 колесные пары).
|
|
Создавая таким образом систему объектов, прежде чем начнем заниматься присущей каждому объекту спецификой, мы получаем возможность четко определить, в каких ситуациях использование абстрактных классов оказывается более предпочтительным, чем использование интерфейсов, и наоборот. Результатов, полученных в этом примере, нельзя достигнуть ни при использовании только интерфейсов, ни при использовании только абстрактного наследования.